From b1f0a3c79b58d1dcacdac798a29778b245e3290d Mon Sep 17 00:00:00 2001 From: buddho Date: Tue, 13 Aug 2024 14:02:38 +0800 Subject: [PATCH 01/41] core: fix cache for receipts (#2643) --- core/blockchain.go | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/core/blockchain.go b/core/blockchain.go index 23d42f2b7f..c50520b203 100644 --- a/core/blockchain.go +++ b/core/blockchain.go @@ -1803,7 +1803,7 @@ func (bc *BlockChain) writeBlockWithState(block *types.Block, receipts []*types. } bc.hc.tdCache.Add(block.Hash(), externTd) bc.blockCache.Add(block.Hash(), block) - bc.receiptsCache.Add(block.Hash(), receipts) + bc.cacheReceipts(block.Hash(), receipts, block) if bc.chainConfig.IsCancun(block.Number(), block.Time()) { bc.sidecarsCache.Add(block.Hash(), block.Sidecars()) } @@ -2320,8 +2320,6 @@ func (bc *BlockChain) insertChain(chain types.Blocks, setHead bool) (int, error) return it.index, err } - bc.cacheReceipts(block.Hash(), receipts, block) - // Update the metrics touched during block commit accountCommitTimer.Update(statedb.AccountCommits) // Account commits are complete, we can mark them storageCommitTimer.Update(statedb.StorageCommits) // Storage commits are complete, we can mark them From 3adcfabb413329359f730c54d192e1d2328fe33c Mon Sep 17 00:00:00 2001 From: easyfold <137396765+easyfold@users.noreply.github.com> Date: Tue, 13 Aug 2024 17:06:07 +0800 Subject: [PATCH 02/41] core/systemcontracts: use vm.StateDB in UpgradeBuildInSystemContract (#2578) --- core/systemcontracts/upgrade.go | 12 ++++++----- core/systemcontracts/upgrade_test.go | 32 ++++++++++++++++++++++++++++ 2 files changed, 39 insertions(+), 5 deletions(-) diff --git a/core/systemcontracts/upgrade.go b/core/systemcontracts/upgrade.go index 714aa16115..83a2aa491a 100644 --- a/core/systemcontracts/upgrade.go +++ b/core/systemcontracts/upgrade.go @@ -4,10 +4,10 @@ import ( "encoding/hex" "fmt" "math/big" + "reflect" "strings" "github.com/ethereum/go-ethereum/common" - "github.com/ethereum/go-ethereum/core/state" "github.com/ethereum/go-ethereum/core/systemcontracts/bohr" "github.com/ethereum/go-ethereum/core/systemcontracts/bruno" "github.com/ethereum/go-ethereum/core/systemcontracts/euler" @@ -23,6 +23,7 @@ import ( "github.com/ethereum/go-ethereum/core/systemcontracts/planck" "github.com/ethereum/go-ethereum/core/systemcontracts/plato" "github.com/ethereum/go-ethereum/core/systemcontracts/ramanujan" + "github.com/ethereum/go-ethereum/core/vm" "github.com/ethereum/go-ethereum/log" "github.com/ethereum/go-ethereum/params" ) @@ -40,7 +41,7 @@ type Upgrade struct { Configs []*UpgradeConfig } -type upgradeHook func(blockNumber *big.Int, contractAddr common.Address, statedb *state.StateDB) error +type upgradeHook func(blockNumber *big.Int, contractAddr common.Address, statedb vm.StateDB) error const ( mainNet = "Mainnet" @@ -789,10 +790,11 @@ func init() { } } -func UpgradeBuildInSystemContract(config *params.ChainConfig, blockNumber *big.Int, lastBlockTime uint64, blockTime uint64, statedb *state.StateDB) { - if config == nil || blockNumber == nil || statedb == nil { +func UpgradeBuildInSystemContract(config *params.ChainConfig, blockNumber *big.Int, lastBlockTime uint64, blockTime uint64, statedb vm.StateDB) { + if config == nil || blockNumber == nil || statedb == nil || reflect.ValueOf(statedb).IsNil() { return } + var network string switch GenesisHash { /* Add mainnet genesis hash */ @@ -876,7 +878,7 @@ func UpgradeBuildInSystemContract(config *params.ChainConfig, blockNumber *big.I */ } -func applySystemContractUpgrade(upgrade *Upgrade, blockNumber *big.Int, statedb *state.StateDB, logger log.Logger) { +func applySystemContractUpgrade(upgrade *Upgrade, blockNumber *big.Int, statedb vm.StateDB, logger log.Logger) { if upgrade == nil { logger.Info("Empty upgrade config", "height", blockNumber.String()) return diff --git a/core/systemcontracts/upgrade_test.go b/core/systemcontracts/upgrade_test.go index 1d8270fd94..3f88d7687b 100644 --- a/core/systemcontracts/upgrade_test.go +++ b/core/systemcontracts/upgrade_test.go @@ -2,9 +2,13 @@ package systemcontracts import ( "crypto/sha256" + "math/big" "testing" "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/core/state" + "github.com/ethereum/go-ethereum/core/vm" + "github.com/ethereum/go-ethereum/params" "github.com/stretchr/testify/require" ) @@ -39,3 +43,31 @@ func TestAllCodesHash(t *testing.T) { allCodeHash := sha256.Sum256(allCodes) require.Equal(t, allCodeHash[:], common.Hex2Bytes("833cc0fc87c46ad8a223e44ccfdc16a51a7e7383525136441bd0c730f06023df")) } + +func TestUpgradeBuildInSystemContractNilInterface(t *testing.T) { + var ( + config = params.BSCChainConfig + blockNumber = big.NewInt(37959559) + lastBlockTime uint64 = 1713419337 + blockTime uint64 = 1713419340 + statedb vm.StateDB + ) + + GenesisHash = params.BSCGenesisHash + + UpgradeBuildInSystemContract(config, blockNumber, lastBlockTime, blockTime, statedb) +} + +func TestUpgradeBuildInSystemContractNilValue(t *testing.T) { + var ( + config = params.BSCChainConfig + blockNumber = big.NewInt(37959559) + lastBlockTime uint64 = 1713419337 + blockTime uint64 = 1713419340 + statedb vm.StateDB = (*state.StateDB)(nil) + ) + + GenesisHash = params.BSCGenesisHash + + UpgradeBuildInSystemContract(config, blockNumber, lastBlockTime, blockTime, statedb) +} From 99a2dd5ed99b7f8afa5499a1a2bbd3a3cd52a81f Mon Sep 17 00:00:00 2001 From: buddho Date: Thu, 15 Aug 2024 11:38:14 +0800 Subject: [PATCH 03/41] internal/debug: remove memsize (#2649) --- cmd/geth/main.go | 2 -- go.mod | 1 - go.sum | 2 -- internal/debug/flags.go | 4 ---- 4 files changed, 9 deletions(-) diff --git a/cmd/geth/main.go b/cmd/geth/main.go index a851c8d373..d4ac750d5b 100644 --- a/cmd/geth/main.go +++ b/cmd/geth/main.go @@ -371,8 +371,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) diff --git a/go.mod b/go.mod index 153f7770ab..55c619ba3b 100644 --- a/go.mod +++ b/go.mod @@ -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 diff --git a/go.sum b/go.sum index 7e8baebe66..e6940c07b4 100644 --- a/go.sum +++ b/go.sum @@ -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= diff --git a/internal/debug/flags.go b/internal/debug/flags.go index dac878a7b1..29f7142587 100644 --- a/internal/debug/flags.go +++ b/internal/debug/flags.go @@ -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 { From 5d19f2182b0a4d9464cd24430f634f842bcfee4f Mon Sep 17 00:00:00 2001 From: buddho Date: Tue, 20 Aug 2024 11:51:32 +0800 Subject: [PATCH 04/41] internal/ethapi: make GetFinalizedHeader monotonically increasing (#2655) --- eth/api_backend.go | 6 +- internal/ethapi/api.go | 76 +++++++++++++++--------- internal/ethapi/api_test.go | 6 +- internal/ethapi/backend.go | 4 +- internal/ethapi/transaction_args_test.go | 2 +- 5 files changed, 56 insertions(+), 38 deletions(-) diff --git a/eth/api_backend.go b/eth/api_backend.go index d72711929d..6a137155ed 100644 --- a/eth/api_backend.go +++ b/eth/api_backend.go @@ -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(¤tHead) + return service.(*parlia.API).GetValidators(¤tHead) } - return 1, nil + return []common.Address{}, errors.New("not supported") } func (b *EthAPIBackend) CurrentHeader() *types.Header { diff --git a/internal/ethapi/api.go b/internal/ethapi/api.go index 1c81ba544c..6a2ac19319 100644 --- a/internal/ethapi/api.go +++ b/internal/ethapi/api.go @@ -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 nil, err + 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(), latestHeader.Number.Int64()-probabilisticFinalized*int64(currentTurnLength)) - return s.GetHeaderByNumber(ctx, rpc.BlockNumber(finalizedBlockNumber)) -} + 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)) -// 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) - } + return finalizedBlockNumber, nil +} - currentTurnLength, err := s.b.CurrentTurnLength() - if err != nil { // impossible - return nil, err - } - fastFinalizedHeader, err := s.b.HeaderByNumber(ctx, rpc.FinalizedBlockNumber) +// 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 } - latestHeader, err := s.b.HeaderByNumber(ctx, rpc.LatestBlockNumber) + return s.GetHeaderByNumber(ctx, rpc.BlockNumber(finalizedBlockNumber)) +} + +// 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 } - finalizedBlockNumber := max(fastFinalizedHeader.Number.Int64(), latestHeader.Number.Int64()-probabilisticFinalized*int64(currentTurnLength)) return s.GetBlockByNumber(ctx, rpc.BlockNumber(finalizedBlockNumber), fullTx) } diff --git a/internal/ethapi/api_test.go b/internal/ethapi/api_test.go index ac467c352a..8f1b8e3b0f 100644 --- a/internal/ethapi/api_test.go +++ b/internal/ethapi/api_test.go @@ -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") } diff --git a/internal/ethapi/backend.go b/internal/ethapi/backend.go index 79492cda85..0cb3fb25cd 100644 --- a/internal/ethapi/backend.go +++ b/internal/ethapi/backend.go @@ -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 diff --git a/internal/ethapi/transaction_args_test.go b/internal/ethapi/transaction_args_test.go index 17bbc49c5a..cc00e839d6 100644 --- a/internal/ethapi/transaction_args_test.go +++ b/internal/ethapi/transaction_args_test.go @@ -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 } From 3bd9a2395c377345ad2297bfe7bcd45bed296cb7 Mon Sep 17 00:00:00 2001 From: buddho Date: Tue, 20 Aug 2024 23:06:49 +0800 Subject: [PATCH 05/41] core: improve readability of the fork choice logic (#2658) --- core/forkchoice.go | 19 +++++++++++++------ 1 file changed, 13 insertions(+), 6 deletions(-) diff --git a/core/forkchoice.go b/core/forkchoice.go index bea7652fa2..4e931ccf50 100644 --- a/core/forkchoice.go +++ b/core/forkchoice.go @@ -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 } From 6cb4be4ebf63755a74e5ccdee842bdbc74731c66 Mon Sep 17 00:00:00 2001 From: Chris Li Date: Wed, 21 Aug 2024 15:37:42 +0800 Subject: [PATCH 06/41] fix: when dataset is pruned and pruneancient is set, the offset is error (#2657) --- core/rawdb/prunedfreezer.go | 18 +++++++----------- 1 file changed, 7 insertions(+), 11 deletions(-) diff --git a/core/rawdb/prunedfreezer.go b/core/rawdb/prunedfreezer.go index b9c18ac2aa..c772ca7630 100644 --- a/core/rawdb/prunedfreezer.go +++ b/core/rawdb/prunedfreezer.go @@ -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 } From c46d7e8bd85ab6503fec62351648dac0a1753895 Mon Sep 17 00:00:00 2001 From: "Dike.w" Date: Thu, 22 Aug 2024 11:07:05 +0800 Subject: [PATCH 07/41] ethclient: fix BlobSidecars api (#2656) --- core/types/blob_sidecar.go | 39 ++++++++++++++++++++++++++++++++++++++ ethclient/ethclient.go | 8 ++++---- 2 files changed, 43 insertions(+), 4 deletions(-) diff --git a/core/types/blob_sidecar.go b/core/types/blob_sidecar.go index d4f63602d0..a97d1ed406 100644 --- a/core/types/blob_sidecar.go +++ b/core/types/blob_sidecar.go @@ -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 +} diff --git a/ethclient/ethclient.go b/ethclient/ethclient.go index bf26c79aa8..8cf50eb528 100644 --- a/ethclient/ethclient.go +++ b/ethclient/ethclient.go @@ -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 From ec2d7e022867014e36d01f5b12b3aa16328c4c7f Mon Sep 17 00:00:00 2001 From: zzzckck <152148891+zzzckck@users.noreply.github.com> Date: Fri, 23 Aug 2024 13:59:56 +0800 Subject: [PATCH 08/41] 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 --- params/config.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/params/config.go b/params/config.go index 2392c643d4..2c73e8dfe7 100644 --- a/params/config.go +++ b/params/config.go @@ -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, From af0204bd6870b1057e2866eb5ac41d5be3170163 Mon Sep 17 00:00:00 2001 From: zzzckck <152148891+zzzckck@users.noreply.github.com> Date: Mon, 26 Aug 2024 16:09:34 +0800 Subject: [PATCH 09/41] faucet: bump and resend faucet transaction if it has been pending for a while (#2665) --- Makefile | 5 ++++ cmd/faucet/faucet.go | 58 +++++++++++++++++++++++++++++++++++++++++--- 2 files changed, 60 insertions(+), 3 deletions(-) diff --git a/Makefile b/Makefile index 30a36697c6..252813ba05 100644 --- a/Makefile +++ b/Makefile @@ -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 diff --git a/cmd/faucet/faucet.go b/cmd/faucet/faucet.go index 25a0cc084a..7c8963dc69 100644 --- a/cmd/faucet/faucet.go +++ b/cmd/faucet/faucet.go @@ -77,6 +77,11 @@ 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 ) var ( @@ -378,7 +383,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.Info("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,7 +405,7 @@ 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 if *captchaToken != "" { @@ -475,7 +484,7 @@ 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) + log.Info("Faucet request valid", "url", msg.URL, "tier", msg.Tier, "user", username, "address", address, "ip", ip) // Ensure the user didn't request funds too recently f.lock.Lock() @@ -605,9 +614,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:] } From 959850218c1ff34ad1b2d840551eccf8b98266c3 Mon Sep 17 00:00:00 2001 From: zzzckck <152148891+zzzckck@users.noreply.github.com> Date: Tue, 27 Aug 2024 11:23:04 +0800 Subject: [PATCH 10/41] release: prepare for release v1.4.14 (#2668) --- CHANGELOG.md | 17 +++++++++++++++++ params/version.go | 2 +- 2 files changed, 18 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index da3e761d02..5907ec247c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,4 +1,21 @@ # 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 prunefreezer’s 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 diff --git a/params/version.go b/params/version.go index 3454448fe5..4327f17d11 100644 --- a/params/version.go +++ b/params/version.go @@ -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 = 14 // Patch version component of the current release VersionMeta = "" // Version metadata to append to the version string ) From d3450f13c9676c4857e09722656a29b21d5ee6ed Mon Sep 17 00:00:00 2001 From: zzzckck <152148891+zzzckck@users.noreply.github.com> Date: Tue, 3 Sep 2024 14:27:53 +0800 Subject: [PATCH 11/41] log: add some p2p log (#2677) --- eth/downloader/downloader.go | 4 ++-- eth/downloader/downloader_test.go | 2 +- eth/handler.go | 4 ++-- eth/sync.go | 2 +- 4 files changed, 6 insertions(+), 6 deletions(-) diff --git a/eth/downloader/downloader.go b/eth/downloader/downloader.go index 09925d7d66..8338fd9316 100644 --- a/eth/downloader/downloader.go +++ b/eth/downloader/downloader.go @@ -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 diff --git a/eth/downloader/downloader_test.go b/eth/downloader/downloader_test.go index 3c113b9134..0a007644d2 100644 --- a/eth/downloader/downloader_test.go +++ b/eth/downloader/downloader_test.go @@ -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) } diff --git a/eth/handler.go b/eth/handler.go index 23dba9e14d..cc3bf382b4 100644 --- a/eth/handler.go +++ b/eth/handler.go @@ -483,13 +483,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()) @@ -632,7 +632,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) diff --git a/eth/sync.go b/eth/sync.go index 3b04d09920..3489b988ee 100644 --- a/eth/sync.go +++ b/eth/sync.go @@ -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 } From 094519d0582bac363018b1f2a1ba06624a2f95a0 Mon Sep 17 00:00:00 2001 From: "Dike.w" Date: Wed, 4 Sep 2024 09:39:01 +0800 Subject: [PATCH 12/41] beaconserver: simulated beacon api server for op-stack (#2678) only some necessary apis are implemented. --- beacon/fakebeacon/api_func.go | 87 ++++++++++++++++++++++++++++ beacon/fakebeacon/handlers.go | 88 +++++++++++++++++++++++++++++ beacon/fakebeacon/server.go | 97 ++++++++++++++++++++++++++++++++ beacon/fakebeacon/server_test.go | 90 +++++++++++++++++++++++++++++ beacon/fakebeacon/utils.go | 65 +++++++++++++++++++++ cmd/geth/config.go | 20 +++++-- cmd/geth/main.go | 7 +++ cmd/utils/flags.go | 20 +++++++ 8 files changed, 470 insertions(+), 4 deletions(-) create mode 100644 beacon/fakebeacon/api_func.go create mode 100644 beacon/fakebeacon/handlers.go create mode 100644 beacon/fakebeacon/server.go create mode 100644 beacon/fakebeacon/server_test.go create mode 100644 beacon/fakebeacon/utils.go diff --git a/beacon/fakebeacon/api_func.go b/beacon/fakebeacon/api_func.go new file mode 100644 index 0000000000..674bf7fb39 --- /dev/null +++ b/beacon/fakebeacon/api_func.go @@ -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 +} diff --git a/beacon/fakebeacon/handlers.go b/beacon/fakebeacon/handlers.go new file mode 100644 index 0000000000..3d3768aa42 --- /dev/null +++ b/beacon/fakebeacon/handlers.go @@ -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 +} diff --git a/beacon/fakebeacon/server.go b/beacon/fakebeacon/server.go new file mode 100644 index 0000000000..91f48a2fbd --- /dev/null +++ b/beacon/fakebeacon/server.go @@ -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}, + }, + } +} diff --git a/beacon/fakebeacon/server_test.go b/beacon/fakebeacon/server_test.go new file mode 100644 index 0000000000..0b74f565ba --- /dev/null +++ b/beacon/fakebeacon/server_test.go @@ -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) +} diff --git a/beacon/fakebeacon/utils.go b/beacon/fakebeacon/utils.go new file mode 100644 index 0000000000..cc6fe889b9 --- /dev/null +++ b/beacon/fakebeacon/utils.go @@ -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) + } + } + } + } +} diff --git a/cmd/geth/config.go b/cmd/geth/config.go index 5c829a2f76..3e0da27edd 100644 --- a/cmd/geth/config.go +++ b/cmd/geth/config.go @@ -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,6 +244,16 @@ 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), diff --git a/cmd/geth/main.go b/cmd/geth/main.go index d4ac750d5b..264f7cb64b 100644 --- a/cmd/geth/main.go +++ b/cmd/geth/main.go @@ -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") diff --git a/cmd/utils/flags.go b/cmd/utils/flags.go index 049908857f..1a0f0a040f 100644 --- a/cmd/utils/flags.go +++ b/cmd/utils/flags.go @@ -37,6 +37,7 @@ import ( "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 +1147,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 ( From 0dab664d98d4249dcf6cc41168ff291423ac3952 Mon Sep 17 00:00:00 2001 From: zzzckck <152148891+zzzckck@users.noreply.github.com> Date: Wed, 4 Sep 2024 16:02:27 +0800 Subject: [PATCH 13/41] 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 --- cmd/geth/main.go | 11 ++++++----- eth/api_miner.go | 2 +- 2 files changed, 7 insertions(+), 6 deletions(-) diff --git a/cmd/geth/main.go b/cmd/geth/main.go index 264f7cb64b..e2c277b64f 100644 --- a/cmd/geth/main.go +++ b/cmd/geth/main.go @@ -450,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) } diff --git a/eth/api_miner.go b/eth/api_miner.go index b8d571a475..56db9e94b1 100644 --- a/eth/api_miner.go +++ b/eth/api_miner.go @@ -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 From f85d19aa8f7247dc049806df35e67702a5f1b692 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 4 Sep 2024 16:12:07 +0800 Subject: [PATCH 14/41] 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. --- .github/workflows/pre-release.yml | 8 ++++---- .github/workflows/release.yml | 8 ++++---- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/.github/workflows/pre-release.yml b/.github/workflows/pre-release.yml index 60c3951a62..b8658f732b 100644 --- a/.github/workflows/pre-release.yml +++ b/.github/workflows/pre-release.yml @@ -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 diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 304d6f5d0a..b0b57e8d90 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -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 From 5c4096fffad24d6d86d7283fd1a1c71f78591998 Mon Sep 17 00:00:00 2001 From: zzzckck <152148891+zzzckck@users.noreply.github.com> Date: Wed, 4 Sep 2024 16:19:01 +0800 Subject: [PATCH 15/41] faucet: with mainnet balance check, 0.002BNB at least (#2672) --- cmd/faucet/faucet.go | 191 +++++++++++++++++++++++++------------------ 1 file changed, 113 insertions(+), 78 deletions(-) diff --git a/cmd/faucet/faucet.go b/cmd/faucet/faucet.go index 7c8963dc69..e83a32835a 100644 --- a/cmd/faucet/faucet.go +++ b/cmd/faucet/faucet.go @@ -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") @@ -82,6 +83,7 @@ var ( resendBatchSize = 3 resendMaxGasPrice = big.NewInt(50 * params.GWei) wsReadTimeout = 5 * time.Minute + minMainnetBalance = big.NewInt(2 * 1e6 * params.GWei) // 0.002 bnb ) var ( @@ -92,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++ { @@ -175,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) } @@ -202,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 @@ -233,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 @@ -242,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) @@ -250,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 } @@ -387,7 +402,7 @@ func (f *faucet) apiHandler(w http.ResponseWriter, r *http.Request) { // 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.Info("read json message failed", "err", err, "ip", ip) + 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/") { @@ -407,7 +422,7 @@ func (f *faucet) apiHandler(w http.ResponseWriter, r *http.Request) { } 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) @@ -484,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, "ip", ip) - // 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 recently, 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 } + log.Info("too frequent funding(ip)", "TimeLeft", common.PrettyDuration(time.Until(ipTimeout)), "ip", ips[len(ips)-2], "ipsStr", ipsStr) + continue + } + 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 + } + log.Info("too frequent funding(id)", "TimeLeft", common.PrettyDuration(time.Until(idTimeout)), "id", id) 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) + // 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 { - tokenInfo, ok := f.bep2eInfos[msg.Symbol] - if !ok { + if balanceMainnet.Cmp(minMainnetBalance) < 0 { 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) + 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 } - 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 { + } + 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() - if err = sendError(wsconn, err); err != nil { - log.Warn("Failed to send transaction creation error to client", "err", err) - return - } + log.Warn("Failed to find symbol", "symbol", msg.Symbol) continue } - // Submit the transaction and mark as funded if successful - if err := f.client.SendTransaction(context.Background(), signed); err != nil { + 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 transmission error to client", "err", err) - return - } + log.Warn("Failed to pack transfer transaction", "err", err) 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 From 24a46de5b27bea4ff1dbb6580bbe02c122a68c27 Mon Sep 17 00:00:00 2001 From: Nicolas Gotchac Date: Wed, 4 Sep 2024 10:22:07 +0200 Subject: [PATCH 16/41] eth: Add sidecars when available to broadcasted current block (#2675) --- eth/sync.go | 3 +++ 1 file changed, 3 insertions(+) diff --git a/eth/sync.go b/eth/sync.go index 3b04d09920..3768422566 100644 --- a/eth/sync.go +++ b/eth/sync.go @@ -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) } } From 1bcdad851f9146756dd9d6d52a635ddf0833f642 Mon Sep 17 00:00:00 2001 From: galaio <12880651+galaio@users.noreply.github.com> Date: Wed, 4 Sep 2024 16:37:43 +0800 Subject: [PATCH 17/41] metrics: add some extra feature flags as node stats; (#2662) --- cmd/geth/config.go | 1 + cmd/utils/flags.go | 63 ++++++++++++++++++++++++++++++++++++++++++++++ core/blockchain.go | 5 ++++ 3 files changed, 69 insertions(+) diff --git a/cmd/geth/config.go b/cmd/geth/config.go index 3e0da27edd..10d2224a14 100644 --- a/cmd/geth/config.go +++ b/cmd/geth/config.go @@ -259,6 +259,7 @@ func makeFullNode(ctx *cli.Context) (*node.Node, ethapi.Backend) { 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 } diff --git a/cmd/utils/flags.go b/cmd/utils/flags.go index 1a0f0a040f..f26ce3881e 100644 --- a/cmd/utils/flags.go +++ b/cmd/utils/flags.go @@ -35,6 +35,8 @@ 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" @@ -2317,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") diff --git a/core/blockchain.go b/core/blockchain.go index c50520b203..b2a56d74bf 100644 --- a/core/blockchain.go +++ b/core/blockchain.go @@ -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) From 03069a7703c6a7330647cab31802ac576fce24fa Mon Sep 17 00:00:00 2001 From: Nicolas Gotchac Date: Wed, 4 Sep 2024 11:29:17 +0200 Subject: [PATCH 18/41] fetcher: Sleep after marking block as done when requeuing Otherwise the node will be waiting for 500ms before the block fetcher keeps processing. --- eth/fetcher/block_fetcher.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/eth/fetcher/block_fetcher.go b/eth/fetcher/block_fetcher.go index fa5a324984..19f8c1ffb8 100644 --- a/eth/fetcher/block_fetcher.go +++ b/eth/fetcher/block_fetcher.go @@ -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 } From e7e5d508b5c8934f527869c06d1b9149bec02cf4 Mon Sep 17 00:00:00 2001 From: zzzckck <152148891+zzzckck@users.noreply.github.com> Date: Thu, 5 Sep 2024 22:01:24 +0800 Subject: [PATCH 19/41] 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. --- miner/miner.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/miner/miner.go b/miner/miner.go index aaef07932d..ebf53199e9 100644 --- a/miner/miner.go +++ b/miner/miner.go @@ -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 From 7de27ca9e94e08af4a0b8aa35fa94e29c12607d0 Mon Sep 17 00:00:00 2001 From: buddho Date: Tue, 10 Sep 2024 11:27:04 +0800 Subject: [PATCH 20/41] CI: nancy ignore CVE-2024-8421 (#2695) --- .nancy-ignore | 1 + 1 file changed, 1 insertion(+) diff --git a/.nancy-ignore b/.nancy-ignore index 0b64e763db..6d058384b6 100644 --- a/.nancy-ignore +++ b/.nancy-ignore @@ -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. \ No newline at end of file From a28262b3ecefd12909538795cf8f5b0a5dd476a2 Mon Sep 17 00:00:00 2001 From: buddho Date: Tue, 10 Sep 2024 16:24:29 +0800 Subject: [PATCH 21/41] miner: limit block size to eth protocol msg size (#2696) --- eth/protocols/eth/protocol.go | 3 ++- miner/bid_simulator.go | 9 +++++++++ miner/worker.go | 19 +++++++++++++++++++ params/protocol_params.go | 2 ++ 4 files changed, 32 insertions(+), 1 deletion(-) diff --git a/eth/protocols/eth/protocol.go b/eth/protocols/eth/protocol.go index d1e07df25c..46bc97fbb8 100644 --- a/eth/protocols/eth/protocol.go +++ b/eth/protocols/eth/protocol.go @@ -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 diff --git a/miner/bid_simulator.go b/miner/bid_simulator.go index f96d3c1a8a..498f1ec2b2 100644 --- a/miner/bid_simulator.go +++ b/miner/bid_simulator.go @@ -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 } diff --git a/miner/worker.go b/miner/worker.go index 8f09819d7d..8513b6a9b6 100644 --- a/miner/worker.go +++ b/miner/worker.go @@ -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 } diff --git a/params/protocol_params.go b/params/protocol_params.go index 65b2d942c1..a032f2759e 100644 --- a/params/protocol_params.go +++ b/params/protocol_params.go @@ -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. From 8bbd8fbf484ef03606cb749ca0184609a8580b66 Mon Sep 17 00:00:00 2001 From: buddho Date: Wed, 11 Sep 2024 10:14:11 +0800 Subject: [PATCH 22/41] consensus/parlia: wait more time when processing huge blocks (#2689) --- consensus/parlia/parlia.go | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/consensus/parlia/parlia.go b/consensus/parlia/parlia.go index 4a79ec344b..79ff3f93af 100644 --- a/consensus/parlia/parlia.go +++ b/consensus/parlia/parlia.go @@ -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 From 44e91bba238b2841723cb703edddfe12225174ed Mon Sep 17 00:00:00 2001 From: zzzckck <152148891+zzzckck@users.noreply.github.com> Date: Thu, 12 Sep 2024 15:10:37 +0800 Subject: [PATCH 23/41] faucet: support customized token (#2687) --- cmd/faucet/customized/README.md | 10 ++++++++++ cmd/faucet/faucet.go | 2 +- 2 files changed, 11 insertions(+), 1 deletion(-) create mode 100644 cmd/faucet/customized/README.md diff --git a/cmd/faucet/customized/README.md b/cmd/faucet/customized/README.md new file mode 100644 index 0000000000..e6f167c9b8 --- /dev/null +++ b/cmd/faucet/customized/README.md @@ -0,0 +1,10 @@ +# 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 \ No newline at end of file diff --git a/cmd/faucet/faucet.go b/cmd/faucet/faucet.go index e83a32835a..918b60a586 100644 --- a/cmd/faucet/faucet.go +++ b/cmd/faucet/faucet.go @@ -500,7 +500,7 @@ func (f *faucet) apiHandler(w http.ResponseWriter, r *http.Request) { continue } - // check #2: check IP and ID(address) to 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() if ipTimeout := f.timeouts[ips[len(ips)-2]]; time.Now().Before(ipTimeout) { From 282aee5856a1ecc31b90d8978c3d585cd5d95766 Mon Sep 17 00:00:00 2001 From: zzzckck <152148891+zzzckck@users.noreply.github.com> Date: Thu, 12 Sep 2024 15:48:11 +0800 Subject: [PATCH 24/41] faucet: add example for custimized token (#2698) --- cmd/faucet/customized/README.md | 8 +++++++- cmd/faucet/customized/demotoken.png | Bin 0 -> 29228 bytes 2 files changed, 7 insertions(+), 1 deletion(-) create mode 100644 cmd/faucet/customized/demotoken.png diff --git a/cmd/faucet/customized/README.md b/cmd/faucet/customized/README.md index e6f167c9b8..c53fa3b33c 100644 --- a/cmd/faucet/customized/README.md +++ b/cmd/faucet/customized/README.md @@ -7,4 +7,10 @@ This is to support some projects with customized tokens that they want to integr 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 \ No newline at end of file +# 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) diff --git a/cmd/faucet/customized/demotoken.png b/cmd/faucet/customized/demotoken.png new file mode 100644 index 0000000000000000000000000000000000000000..1eff3f32d8a8bf567bb94d8611d0c78ff177b504 GIT binary patch literal 29228 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 IM6N<$f&p_+IsgCw literal 0 HcmV?d00001 From 3e44dcaa558a0722b1f0447bf2ebde6e5637f3e9 Mon Sep 17 00:00:00 2001 From: tiaoxizhan Date: Sat, 14 Sep 2024 09:12:56 +0800 Subject: [PATCH 25/41] chore: add missing symbols in comment (#2704) --- crypto/bn256/cloudflare/gfp12.go | 2 +- crypto/bn256/cloudflare/gfp2.go | 2 +- crypto/bn256/cloudflare/gfp6.go | 2 +- crypto/bn256/google/gfp12.go | 2 +- crypto/bn256/google/gfp2.go | 2 +- crypto/bn256/google/gfp6.go | 2 +- 6 files changed, 6 insertions(+), 6 deletions(-) diff --git a/crypto/bn256/cloudflare/gfp12.go b/crypto/bn256/cloudflare/gfp12.go index 93fb368a7b..4e080f3ad3 100644 --- a/crypto/bn256/cloudflare/gfp12.go +++ b/crypto/bn256/cloudflare/gfp12.go @@ -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 ( diff --git a/crypto/bn256/cloudflare/gfp2.go b/crypto/bn256/cloudflare/gfp2.go index 90a89e8b47..094fb1460e 100644 --- a/crypto/bn256/cloudflare/gfp2.go +++ b/crypto/bn256/cloudflare/gfp2.go @@ -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 diff --git a/crypto/bn256/cloudflare/gfp6.go b/crypto/bn256/cloudflare/gfp6.go index a42734911c..72f552cd35 100644 --- a/crypto/bn256/cloudflare/gfp6.go +++ b/crypto/bn256/cloudflare/gfp6.go @@ -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 τ³=ξ diff --git a/crypto/bn256/google/gfp12.go b/crypto/bn256/google/gfp12.go index f084eddf21..39b407e80a 100644 --- a/crypto/bn256/google/gfp12.go +++ b/crypto/bn256/google/gfp12.go @@ -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 ( diff --git a/crypto/bn256/google/gfp2.go b/crypto/bn256/google/gfp2.go index 3981f6cb4f..9cc854e3f6 100644 --- a/crypto/bn256/google/gfp2.go +++ b/crypto/bn256/google/gfp2.go @@ -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 ( diff --git a/crypto/bn256/google/gfp6.go b/crypto/bn256/google/gfp6.go index 218856617c..3fe3d344ca 100644 --- a/crypto/bn256/google/gfp6.go +++ b/crypto/bn256/google/gfp6.go @@ -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 ( From 34059cb14408d93314adab51ab40d67a36377f2b Mon Sep 17 00:00:00 2001 From: WMQ <46511820+wangminqi@users.noreply.github.com> Date: Wed, 18 Sep 2024 11:51:59 +0800 Subject: [PATCH 26/41] faucet: update DIN token faucet support (#2706) --- cmd/faucet/customized/DIN.png | Bin 0 -> 10695 bytes cmd/faucet/customized/README.md | 7 +++++++ 2 files changed, 7 insertions(+) create mode 100644 cmd/faucet/customized/DIN.png diff --git a/cmd/faucet/customized/DIN.png b/cmd/faucet/customized/DIN.png new file mode 100644 index 0000000000000000000000000000000000000000..be36433308690060c6663c244d21a96c4ae8f547 GIT binary patch literal 10695 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 literal 0 HcmV?d00001 diff --git a/cmd/faucet/customized/README.md b/cmd/faucet/customized/README.md index c53fa3b33c..65a5a9b64c 100644 --- a/cmd/faucet/customized/README.md +++ b/cmd/faucet/customized/README.md @@ -14,3 +14,10 @@ We will review the request, and once it is approved, the faucet tool will start - 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) From 21faa2de3f7d11bfa6e0913c54dc2705abb660b1 Mon Sep 17 00:00:00 2001 From: zzzckck <152148891+zzzckck@users.noreply.github.com> Date: Wed, 18 Sep 2024 14:34:01 +0800 Subject: [PATCH 27/41] release: prepare for release v1.4.15 (#2700) --- CHANGELOG.md | 22 ++++++++++++++++++++++ params/version.go | 2 +- 2 files changed, 23 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 5907ec247c..513ffbc2ff 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,4 +1,26 @@ # 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 diff --git a/params/version.go b/params/version.go index 4327f17d11..4fc05b1ed8 100644 --- a/params/version.go +++ b/params/version.go @@ -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 = 14 // 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 ) From 9cbac8436305b8c5d2518284e8e84ec88d473922 Mon Sep 17 00:00:00 2001 From: zzzckck <152148891+zzzckck@users.noreply.github.com> Date: Wed, 18 Sep 2024 16:56:10 +0800 Subject: [PATCH 28/41] 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 --- README.md | 26 ++++++-------------------- 1 file changed, 6 insertions(+), 20 deletions(-) diff --git a/README.md b/README.md index 360ba0d7ba..d26fec81c4 100644 --- a/README.md +++ b/README.md @@ -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 From d141ff06c36b0ddc8469d75f82344f2ece2f5853 Mon Sep 17 00:00:00 2001 From: buddh0 Date: Wed, 4 Sep 2024 16:36:37 +0800 Subject: [PATCH 29/41] Revert "eth/handler: check lists in body before broadcast blocks (#2461)" This reverts commit 0c0958ff8709eab1d5d4d0adaa81c09a89ec75d9. --- core/block_validator.go | 46 ++++++++++++++++++----------------------- eth/handler.go | 34 ++++++++++++++++-------------- 2 files changed, 39 insertions(+), 41 deletions(-) diff --git a/core/block_validator.go b/core/block_validator.go index b82965a99d..d15e2cd786 100644 --- a/core/block_validator.go +++ b/core/block_validator.go @@ -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() { diff --git a/eth/handler.go b/eth/handler.go index cc3bf382b4..f65515166d 100644 --- a/eth/handler.go +++ b/eth/handler.go @@ -320,22 +320,26 @@ func newHandler(config *handlerConfig) (*handler, error) { } broadcastBlockWithCheck := func(block *types.Block, propagate bool) { + // All the block fetcher activities should be disabled + // after the transition. Print the warning log. + if h.merger.PoSFinalized() { + log.Warn("Unexpected validation activity", "hash", block.Hash(), "number", block.Number()) + return + } + // Reject all the PoS style headers in the first place. No matter + // the chain has finished the transition or not, the PoS headers + // should only come from the trusted consensus layer instead of + // p2p network. + if beacon, ok := h.chain.Engine().(*beacon.Beacon); ok { + if beacon.IsPoSHeader(block.Header()) { + log.Warn("unexpected post-merge header") + return + } + } 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 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) From 5289ecdfe2185a76c310e1c424b2177f3de43034 Mon Sep 17 00:00:00 2001 From: buddh0 Date: Wed, 4 Sep 2024 16:39:15 +0800 Subject: [PATCH 30/41] eth/protocols: add Withdrawals check before broadcastBlock --- eth/handler.go | 19 ++++--------------- 1 file changed, 4 insertions(+), 15 deletions(-) diff --git a/eth/handler.go b/eth/handler.go index f65515166d..f26162024b 100644 --- a/eth/handler.go +++ b/eth/handler.go @@ -320,23 +320,12 @@ func newHandler(config *handlerConfig) (*handler, error) { } broadcastBlockWithCheck := func(block *types.Block, propagate bool) { - // All the block fetcher activities should be disabled - // after the transition. Print the warning log. - if h.merger.PoSFinalized() { - log.Warn("Unexpected validation activity", "hash", block.Hash(), "number", block.Number()) - return - } - // Reject all the PoS style headers in the first place. No matter - // the chain has finished the transition or not, the PoS headers - // should only come from the trusted consensus layer instead of - // p2p network. - if beacon, ok := h.chain.Engine().(*beacon.Beacon); ok { - if beacon.IsPoSHeader(block.Header()) { - log.Warn("unexpected post-merge header") + if propagate { + 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 propagate { 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 From 58b4212c093be388781e9cb16b2158974e7f252b Mon Sep 17 00:00:00 2001 From: NathanBSC Date: Fri, 26 Jul 2024 16:31:38 +0800 Subject: [PATCH 31/41] miner: define config for malicious behaviour --- miner/malicious_behaviour.go | 15 +++++++++++++++ 1 file changed, 15 insertions(+) create mode 100644 miner/malicious_behaviour.go diff --git a/miner/malicious_behaviour.go b/miner/malicious_behaviour.go new file mode 100644 index 0000000000..3f481c0eb6 --- /dev/null +++ b/miner/malicious_behaviour.go @@ -0,0 +1,15 @@ +package miner + +type MBConfig struct { + DoubleSign bool // Generate two consecutive blocks for the same parent block + SkipOffsetInturn uint64 // Skip block production for in-turn validators at a specified offset + BroadcastDelayBlocks uint64 // Delay broadcasting mined blocks by a specified number of blocks + LastBlockMiningTime uint64 // Mining time (milliseconds) for the last block in every turn +} + +var DefaultMBConfig = MBConfig{ + DoubleSign: false, + SkipOffsetInturn: 100, + BroadcastDelayBlocks: 0, + LastBlockMiningTime: 2500, +} From 29468f511ed8ac64fec1fda645f0f5658a16dceb Mon Sep 17 00:00:00 2001 From: NathanBSC Date: Fri, 26 Jul 2024 16:41:34 +0800 Subject: [PATCH 32/41] miner: define logic for SkipOffsetInturn --- miner/gen_mb_config.go | 46 ++++++++++++++++++++++++++++++++++++ miner/malicious_behaviour.go | 14 +++++++---- miner/miner.go | 2 ++ miner/worker.go | 20 ++++++++++++++++ 4 files changed, 77 insertions(+), 5 deletions(-) create mode 100644 miner/gen_mb_config.go diff --git a/miner/gen_mb_config.go b/miner/gen_mb_config.go new file mode 100644 index 0000000000..cd2c8158b6 --- /dev/null +++ b/miner/gen_mb_config.go @@ -0,0 +1,46 @@ +// Code generated by github.com/fjl/gencodec. DO NOT EDIT. + +package miner + +// MarshalTOML marshals as TOML. +func (m MBConfig) MarshalTOML() (interface{}, error) { + type MBConfig struct { + DoubleSign bool + SkipOffsetInturn *uint64 `toml:",omitempty"` + BroadcastDelayBlocks uint64 + LastBlockMiningTime uint64 + } + var enc MBConfig + enc.DoubleSign = m.DoubleSign + enc.SkipOffsetInturn = m.SkipOffsetInturn + enc.BroadcastDelayBlocks = m.BroadcastDelayBlocks + enc.LastBlockMiningTime = m.LastBlockMiningTime + return &enc, nil +} + +// UnmarshalTOML unmarshals from TOML. +func (m *MBConfig) UnmarshalTOML(unmarshal func(interface{}) error) error { + type MBConfig struct { + DoubleSign *bool + SkipOffsetInturn *uint64 `toml:",omitempty"` + BroadcastDelayBlocks *uint64 + LastBlockMiningTime *uint64 + } + var dec MBConfig + if err := unmarshal(&dec); err != nil { + return err + } + if dec.DoubleSign != nil { + m.DoubleSign = *dec.DoubleSign + } + if dec.SkipOffsetInturn != nil { + m.SkipOffsetInturn = dec.SkipOffsetInturn + } + if dec.BroadcastDelayBlocks != nil { + m.BroadcastDelayBlocks = *dec.BroadcastDelayBlocks + } + if dec.LastBlockMiningTime != nil { + m.LastBlockMiningTime = *dec.LastBlockMiningTime + } + return nil +} diff --git a/miner/malicious_behaviour.go b/miner/malicious_behaviour.go index 3f481c0eb6..474d034cf4 100644 --- a/miner/malicious_behaviour.go +++ b/miner/malicious_behaviour.go @@ -1,15 +1,19 @@ package miner +//go:generate go run github.com/fjl/gencodec -type MBConfig -formats toml -out gen_mb_config.go type MBConfig struct { - DoubleSign bool // Generate two consecutive blocks for the same parent block - SkipOffsetInturn uint64 // Skip block production for in-turn validators at a specified offset - BroadcastDelayBlocks uint64 // Delay broadcasting mined blocks by a specified number of blocks - LastBlockMiningTime uint64 // Mining time (milliseconds) for the last block in every turn + // Generate two consecutive blocks for the same parent block + DoubleSign bool + // Skip block production for in-turn validators at a specified offset + SkipOffsetInturn *uint64 `toml:",omitempty"` + // Delay broadcasting mined blocks by a specified number of blocks + BroadcastDelayBlocks uint64 + // Mining time (milliseconds) for the last block in every turn + LastBlockMiningTime uint64 } var DefaultMBConfig = MBConfig{ DoubleSign: false, - SkipOffsetInturn: 100, BroadcastDelayBlocks: 0, LastBlockMiningTime: 2500, } diff --git a/miner/miner.go b/miner/miner.go index ebf53199e9..80c981fa49 100644 --- a/miner/miner.go +++ b/miner/miner.go @@ -58,6 +58,7 @@ type Config struct { DisableVoteAttestation bool // Whether to skip assembling vote attestation Mev MevConfig // Mev configuration + MB MBConfig // Malicious behavior configuration } // DefaultConfig contains default settings for miner. @@ -74,6 +75,7 @@ var DefaultConfig = Config{ DelayLeftOver: 50 * time.Millisecond, Mev: DefaultMevConfig, + MB: DefaultMBConfig, } // Miner creates blocks and searches for proof-of-work values. diff --git a/miner/worker.go b/miner/worker.go index 8513b6a9b6..54b6e3ba23 100644 --- a/miner/worker.go +++ b/miner/worker.go @@ -43,6 +43,7 @@ import ( "github.com/ethereum/go-ethereum/log" "github.com/ethereum/go-ethereum/metrics" "github.com/ethereum/go-ethereum/params" + "github.com/ethereum/go-ethereum/rpc" "github.com/ethereum/go-ethereum/trie" ) @@ -1208,6 +1209,25 @@ func (w *worker) commitWork(interruptCh chan int32, timestamp int64) { return } } + if w.config.MB.SkipOffsetInturn != nil { + if w.inTurn() { + if p, ok := w.engine.(*parlia.Parlia); ok { + service := p.APIs(w.chain)[0].Service + latestBlockNumber := rpc.LatestBlockNumber + currentTurnLength, err := service.(*parlia.API).GetTurnLength(&latestBlockNumber) + if err == nil { + currentHeader := w.chain.CurrentBlock() + blockToMine := currentHeader.Number.Uint64() + 1 + if *w.config.MB.SkipOffsetInturn == blockToMine%uint64(currentTurnLength) { + log.Debug("skip commitWork", "blockNumber", blockToMine) + return + } + } else { + log.Error("commitWork|GetTurnLength", "err", err) + } + } + } + } stopTimer := time.NewTimer(0) defer stopTimer.Stop() From 2e71995ff550cb06f9f727ae71d0c1204d2468eb Mon Sep 17 00:00:00 2001 From: NathanBSC Date: Tue, 30 Jul 2024 10:59:58 +0800 Subject: [PATCH 33/41] miner: define logic for DoubleSign --- consensus/parlia/parlia.go | 17 +++++++++++++++++ miner/worker.go | 18 ++++++++++++++++++ 2 files changed, 35 insertions(+) diff --git a/consensus/parlia/parlia.go b/consensus/parlia/parlia.go index 79ff3f93af..8a8b4aca83 100644 --- a/consensus/parlia/parlia.go +++ b/consensus/parlia/parlia.go @@ -1549,6 +1549,23 @@ func (p *Parlia) Delay(chain consensus.ChainReader, header *types.Header, leftOv return &delay } +// AssembleSignature assemble the signature for block header +func (p *Parlia) AssembleSignature(block *types.Block) (*types.Block, error) { + header := block.Header() + // Don't hold the val fields for the entire sealing procedure + p.lock.RLock() + val, signFn := p.val, p.signFn + p.lock.RUnlock() + sig, err := signFn(accounts.Account{Address: val}, accounts.MimetypeParlia, ParliaRLP(header, p.chainConfig.ChainID)) + if err != nil { + log.Error("Sign for the block header failed when sealing", "err", err) + return nil, err + } + copy(header.Extra[len(header.Extra)-extraSeal:], sig) + block = block.WithSeal(header) + return block, nil +} + // Seal implements consensus.Engine, attempting to create a sealed block using // the local signing credentials. func (p *Parlia) Seal(chain consensus.ChainHeaderReader, block *types.Block, results chan<- *types.Block, stop <-chan struct{}) error { diff --git a/miner/worker.go b/miner/worker.go index 54b6e3ba23..6709164e98 100644 --- a/miner/worker.go +++ b/miner/worker.go @@ -687,6 +687,24 @@ func (w *worker) resultLoop() { log.Info("Successfully sealed new block", "number", block.Number(), "sealhash", sealhash, "hash", hash, "elapsed", common.PrettyDuration(time.Since(task.createdAt))) w.mux.Post(core.NewMinedBlockEvent{Block: block}) + if p, ok := w.engine.(*parlia.Parlia); ok { + if w.config.MB.DoubleSign { + shadowHeader := block.Header() + shadowHeader.Extra[0] = 'd' + shadowHeader.Extra[1] = 's' + shadowBlock := types.NewBlockWithHeader(shadowHeader).WithBody(block.Transactions(), block.Uncles()).WithWithdrawals(block.Withdrawals()).WithSidecars(block.Sidecars()) + shadowBlock, err := p.AssembleSignature(shadowBlock) + if err == nil { + w.mux.Post(core.NewMinedBlockEvent{Block: shadowBlock}) + sealhash := w.engine.SealHash(shadowBlock.Header()) + hash := shadowBlock.Hash() + log.Info("Successfully sealed new block", "number", shadowBlock.Number(), "sealhash", sealhash, "hash", hash, + "elapsed", common.PrettyDuration(time.Since(task.createdAt))) + } else { + log.Info("Failed to AssembleSignature", "err", err) + } + } + } case <-w.exitCh: return From d8042915d13a0f40f37799801a264007e8b48c64 Mon Sep 17 00:00:00 2001 From: NathanBSC Date: Wed, 31 Jul 2024 19:25:19 +0800 Subject: [PATCH 34/41] miner: define logic for BroadcastDelayBlocks --- miner/malicious_behaviour.go | 2 +- miner/worker.go | 71 +++++++++++++++++++++++++++++++++++- 2 files changed, 70 insertions(+), 3 deletions(-) diff --git a/miner/malicious_behaviour.go b/miner/malicious_behaviour.go index 474d034cf4..39bdb3c2f6 100644 --- a/miner/malicious_behaviour.go +++ b/miner/malicious_behaviour.go @@ -6,7 +6,7 @@ type MBConfig struct { DoubleSign bool // Skip block production for in-turn validators at a specified offset SkipOffsetInturn *uint64 `toml:",omitempty"` - // Delay broadcasting mined blocks by a specified number of blocks + // Delay broadcasting mined blocks by a specified number of blocks, only for in turn validators BroadcastDelayBlocks uint64 // Mining time (milliseconds) for the last block in every turn LastBlockMiningTime uint64 diff --git a/miner/worker.go b/miner/worker.go index 6709164e98..0269dd8388 100644 --- a/miner/worker.go +++ b/miner/worker.go @@ -255,6 +255,10 @@ type worker struct { fullTaskHook func() // Method to call before pushing the full sealing task. resubmitHook func(time.Duration, time.Duration) // Method to call upon updating resubmitting interval. recentMinedBlocks *lru.Cache + + // Test purpose + delayedBlocksForBroadcast []*types.Block + delayedMu sync.RWMutex } func newWorker(config *Config, chainConfig *params.ChainConfig, engine consensus.Engine, eth Backend, mux *event.TypeMux, isLocalBlock func(header *types.Header) bool, init bool) *worker { @@ -310,6 +314,11 @@ func newWorker(config *Config, chainConfig *params.ChainConfig, engine consensus go worker.resultLoop() go worker.taskLoop() + if worker.config.MB.BroadcastDelayBlocks > 0 { + worker.wg.Add(1) + go worker.delayBlocksBroadcastLoop() + } + // Submit first work to initialize pending state. if init { worker.startCh <- struct{}{} @@ -671,6 +680,7 @@ func (w *worker) resultLoop() { w.recentMinedBlocks.Add(block.NumberU64(), []common.Hash{block.ParentHash()}) } + inturn := w.inTurn() // Commit block and state to database. task.state.SetExpectedStateRoot(block.Root()) start := time.Now() @@ -686,7 +696,7 @@ func (w *worker) resultLoop() { writeBlockTimer.UpdateSince(start) log.Info("Successfully sealed new block", "number", block.Number(), "sealhash", sealhash, "hash", hash, "elapsed", common.PrettyDuration(time.Since(task.createdAt))) - w.mux.Post(core.NewMinedBlockEvent{Block: block}) + w.postBlock(block, inturn) if p, ok := w.engine.(*parlia.Parlia); ok { if w.config.MB.DoubleSign { shadowHeader := block.Header() @@ -695,7 +705,7 @@ func (w *worker) resultLoop() { shadowBlock := types.NewBlockWithHeader(shadowHeader).WithBody(block.Transactions(), block.Uncles()).WithWithdrawals(block.Withdrawals()).WithSidecars(block.Sidecars()) shadowBlock, err := p.AssembleSignature(shadowBlock) if err == nil { - w.mux.Post(core.NewMinedBlockEvent{Block: shadowBlock}) + w.postBlock(shadowBlock, inturn) sealhash := w.engine.SealHash(shadowBlock.Header()) hash := shadowBlock.Hash() log.Info("Successfully sealed new block", "number", shadowBlock.Number(), "sealhash", sealhash, "hash", hash, @@ -712,6 +722,63 @@ func (w *worker) resultLoop() { } } +func (w *worker) postBlock(block *types.Block, inTurn bool) { + if w.config.MB.BroadcastDelayBlocks > 0 && inTurn { + w.delayedMu.Lock() + w.delayedBlocksForBroadcast = append(w.delayedBlocksForBroadcast, block) + w.delayedMu.Unlock() + } else { + w.mux.Post(core.NewMinedBlockEvent{Block: block}) + } +} +func (w *worker) delayBlocksBroadcastLoop() { + defer w.wg.Done() + + for { + if len(w.delayedBlocksForBroadcast) > 0 { + w.delayedMu.Lock() + + currentBlock := w.chain.CurrentBlock() + currentBlockNum := currentBlock.Number.Uint64() + + delayTime := (w.config.MB.BroadcastDelayBlocks - 1) * w.chainConfig.Parlia.Period + if p, ok := w.engine.(*parlia.Parlia); ok { + service := p.APIs(w.chain)[0].Service + latestBlockNumber := rpc.LatestBlockNumber + currentTurnLength, err := service.(*parlia.API).GetTurnLength(&latestBlockNumber) + nonInTurnBackoff := w.config.MB.BroadcastDelayBlocks + if err == nil { + if w.config.MB.BroadcastDelayBlocks > uint64(currentTurnLength) { + // suppose extra blocks are generated by in turn validators + nonInTurnBackoff = uint64(currentTurnLength) + } + } + delayTime += nonInTurnBackoff + } + + firstBlock := w.delayedBlocksForBroadcast[0] + if uint64(time.Now().Unix()) >= (firstBlock.Time() + delayTime) { + time.Sleep(500 * time.Microsecond) + for _, block := range w.delayedBlocksForBroadcast { + w.mux.Post(core.NewMinedBlockEvent{Block: block}) + log.Debug("delayBlocksBroadcastLoop", "number", block.Number(), "hash", block.Hash(), + "time", block.Time(), "now", uint64(time.Now().Unix()), "currentBlockNum", currentBlockNum) + } + w.delayedBlocksForBroadcast = make([]*types.Block, 0) + } + + w.delayedMu.Unlock() + } + + select { + case <-w.exitCh: + return + default: + time.Sleep(100 * time.Millisecond) + } + } +} + // makeEnv creates a new environment for the sealing block. func (w *worker) makeEnv(parent *types.Header, header *types.Header, coinbase common.Address, prevEnv *environment) (*environment, error) { From 6c9c1ad56b38b960fad01f2b58e7c978d6aacc0d Mon Sep 17 00:00:00 2001 From: NathanBSC Date: Thu, 1 Aug 2024 19:35:44 +0800 Subject: [PATCH 35/41] miner: define logic LastBlockMiningTime --- miner/worker.go | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/miner/worker.go b/miner/worker.go index 0269dd8388..c3e4a7325c 100644 --- a/miner/worker.go +++ b/miner/worker.go @@ -1351,6 +1351,20 @@ LOOP: workList = append(workList, work) delay := w.engine.Delay(w.chain, work.header, &w.config.DelayLeftOver) + if w.config.MB.LastBlockMiningTime > w.chainConfig.Parlia.Period*1000/2 { + if p, ok := w.engine.(*parlia.Parlia); ok { + service := p.APIs(w.chain)[0].Service + latestBlockNumber := rpc.LatestBlockNumber + currentTurnLength, err := service.(*parlia.API).GetTurnLength(&latestBlockNumber) + if err == nil && (work.header.Number.Uint64()+1)%uint64(currentTurnLength) == 0 { + *delay += time.Duration((w.config.MB.LastBlockMiningTime - w.chainConfig.Parlia.Period*1000/2) * uint64(time.Millisecond)) + timeLeft := time.Until(time.Unix(int64(work.header.Time), 0)) + if *delay > timeLeft { + *delay = timeLeft + } + } + } + } if delay == nil { log.Warn("commitWork delay is nil, something is wrong") stopTimer = nil From 6b574fe08f718f0a224811f209444c439471e60c Mon Sep 17 00:00:00 2001 From: NathanBSC Date: Fri, 2 Aug 2024 17:39:14 +0800 Subject: [PATCH 36/41] api: support set malicious behavior config for miner via prc --- eth/api_miner.go | 30 ++++++++++++++++++++++++++++++ miner/malicious_behaviour.go | 2 +- miner/miner.go | 24 ++++++++++++++++++++++++ 3 files changed, 55 insertions(+), 1 deletion(-) diff --git a/eth/api_miner.go b/eth/api_miner.go index 56db9e94b1..802c8f0b44 100644 --- a/eth/api_miner.go +++ b/eth/api_miner.go @@ -20,6 +20,7 @@ import ( "math/big" "time" + "github.com/ethereum/go-ethereum/miner" "github.com/ethereum/go-ethereum/params" "github.com/ethereum/go-ethereum/common" @@ -117,3 +118,32 @@ func (api *MinerAPI) AddBuilder(builder common.Address, url string) error { func (api *MinerAPI) RemoveBuilder(builder common.Address) error { return api.e.APIBackend.RemoveBuilder(builder) } + +func (api *MinerAPI) MBConfig() miner.MBConfig { + return api.e.Miner().MBConfig() +} + +func (api *MinerAPI) ResetMaliciousBehavior() miner.MBConfig { + api.e.Miner().ResetMaliciousBehavior() + return api.e.Miner().MBConfig() +} + +func (api *MinerAPI) SetDoubleSign(on bool) miner.MBConfig { + api.e.Miner().SetDoubleSign(on) + return api.e.Miner().MBConfig() +} + +func (api *MinerAPI) SetSkipOffsetInturn(offset uint64) miner.MBConfig { + api.e.Miner().SetSkipOffsetInturn(offset) + return api.e.Miner().MBConfig() +} + +func (api *MinerAPI) SetBroadcastDelayBlocks(num uint64) miner.MBConfig { + api.e.Miner().SetBroadcastDelayBlocks(num) + return api.e.Miner().MBConfig() +} + +func (api *MinerAPI) SetLastBlockMiningTime(time uint64) miner.MBConfig { + api.e.Miner().SetLastBlockMiningTime(time) + return api.e.Miner().MBConfig() +} diff --git a/miner/malicious_behaviour.go b/miner/malicious_behaviour.go index 39bdb3c2f6..0fb7e4fc8f 100644 --- a/miner/malicious_behaviour.go +++ b/miner/malicious_behaviour.go @@ -15,5 +15,5 @@ type MBConfig struct { var DefaultMBConfig = MBConfig{ DoubleSign: false, BroadcastDelayBlocks: 0, - LastBlockMiningTime: 2500, + LastBlockMiningTime: 0, } diff --git a/miner/miner.go b/miner/miner.go index 80c981fa49..8bdc68a6f8 100644 --- a/miner/miner.go +++ b/miner/miner.go @@ -287,6 +287,30 @@ func (miner *Miner) SetGasCeil(ceil uint64) { miner.worker.setGasCeil(ceil) } +func (miner *Miner) MBConfig() MBConfig { + return miner.worker.config.MB +} + +func (miner *Miner) ResetMaliciousBehavior() { + miner.worker.config.MB = DefaultMBConfig +} + +func (miner *Miner) SetDoubleSign(on bool) { + miner.worker.config.MB.DoubleSign = on +} + +func (miner *Miner) SetSkipOffsetInturn(offset uint64) { + miner.worker.config.MB.SkipOffsetInturn = &offset +} + +func (miner *Miner) SetBroadcastDelayBlocks(num uint64) { + miner.worker.config.MB.BroadcastDelayBlocks = num +} + +func (miner *Miner) SetLastBlockMiningTime(time uint64) { + miner.worker.config.MB.LastBlockMiningTime = time +} + // SubscribePendingLogs starts delivering logs from pending transactions // to the given channel. func (miner *Miner) SubscribePendingLogs(ch chan<- []*types.Log) event.Subscription { From 3bed4d1d75af0e2329ac471644ac33118b519d6f Mon Sep 17 00:00:00 2001 From: NathanBSC Date: Wed, 7 Aug 2024 17:17:24 +0800 Subject: [PATCH 37/41] miner: change log level --- miner/worker.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/miner/worker.go b/miner/worker.go index c3e4a7325c..81c04c5807 100644 --- a/miner/worker.go +++ b/miner/worker.go @@ -761,7 +761,7 @@ func (w *worker) delayBlocksBroadcastLoop() { time.Sleep(500 * time.Microsecond) for _, block := range w.delayedBlocksForBroadcast { w.mux.Post(core.NewMinedBlockEvent{Block: block}) - log.Debug("delayBlocksBroadcastLoop", "number", block.Number(), "hash", block.Hash(), + log.Info("delayBlocksBroadcastLoop", "number", block.Number(), "hash", block.Hash(), "time", block.Time(), "now", uint64(time.Now().Unix()), "currentBlockNum", currentBlockNum) } w.delayedBlocksForBroadcast = make([]*types.Block, 0) @@ -1304,7 +1304,7 @@ func (w *worker) commitWork(interruptCh chan int32, timestamp int64) { currentHeader := w.chain.CurrentBlock() blockToMine := currentHeader.Number.Uint64() + 1 if *w.config.MB.SkipOffsetInturn == blockToMine%uint64(currentTurnLength) { - log.Debug("skip commitWork", "blockNumber", blockToMine) + log.Info("skip commitWork", "blockNumber", blockToMine) return } } else { From c3f8c10a0cb61fbef3ec51079e4db99b252e5b35 Mon Sep 17 00:00:00 2001 From: NathanBSC Date: Wed, 7 Aug 2024 17:39:08 +0800 Subject: [PATCH 38/41] miner: ensure delayBlocksBroadcast loop started --- miner/worker.go | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/miner/worker.go b/miner/worker.go index 81c04c5807..df83f8e0d6 100644 --- a/miner/worker.go +++ b/miner/worker.go @@ -313,11 +313,8 @@ func newWorker(config *Config, chainConfig *params.ChainConfig, engine consensus go worker.newWorkLoop(recommit) go worker.resultLoop() go worker.taskLoop() - - if worker.config.MB.BroadcastDelayBlocks > 0 { - worker.wg.Add(1) - go worker.delayBlocksBroadcastLoop() - } + worker.wg.Add(1) + go worker.delayBlocksBroadcastLoop() // Submit first work to initialize pending state. if init { @@ -735,7 +732,7 @@ func (w *worker) delayBlocksBroadcastLoop() { defer w.wg.Done() for { - if len(w.delayedBlocksForBroadcast) > 0 { + if len(w.delayedBlocksForBroadcast) > 0 && w.config.MB.BroadcastDelayBlocks > 0 { w.delayedMu.Lock() currentBlock := w.chain.CurrentBlock() From 467791fd87853e78d07c4478d3326f9603e66dff Mon Sep 17 00:00:00 2001 From: buddh0 Date: Tue, 13 Aug 2024 17:59:52 +0800 Subject: [PATCH 39/41] api: support enable/disable voting via rpc --- core/vote/vote_manager.go | 6 ++++++ core/vote/vote_pool_test.go | 1 + eth/api_miner.go | 5 +++++ eth/backend.go | 1 + miner/gen_mb_config.go | 6 ++++++ miner/malicious_behaviour.go | 3 +++ miner/miner.go | 8 ++++++++ 7 files changed, 30 insertions(+) diff --git a/core/vote/vote_manager.go b/core/vote/vote_manager.go index 891785482b..35b3412f47 100644 --- a/core/vote/vote_manager.go +++ b/core/vote/vote_manager.go @@ -31,6 +31,7 @@ var notContinuousJustified = metrics.NewRegisteredCounter("votesManager/notConti // Backend wraps all methods required for voting. type Backend interface { IsMining() bool + VoteEnabled() bool EventMux() *event.TypeMux } @@ -136,6 +137,11 @@ func (voteManager *VoteManager) loop() { log.Debug("skip voting because mining is disabled, continue") continue } + if !voteManager.eth.VoteEnabled() { + log.Debug("skip voting because voting is disabled, continue") + continue + } + blockCountSinceMining++ if blockCountSinceMining <= blocksNumberSinceMining { log.Debug("skip voting", "blockCountSinceMining", blockCountSinceMining, "blocksNumberSinceMining", blocksNumberSinceMining) diff --git a/core/vote/vote_pool_test.go b/core/vote/vote_pool_test.go index bb8374e90f..68ee4e8ae7 100644 --- a/core/vote/vote_pool_test.go +++ b/core/vote/vote_pool_test.go @@ -77,6 +77,7 @@ func newTestBackend() *testBackend { return &testBackend{eventMux: new(event.TypeMux)} } func (b *testBackend) IsMining() bool { return true } +func (b *testBackend) VoteEnabled() bool { return true } func (b *testBackend) EventMux() *event.TypeMux { return b.eventMux } func (p *mockPOSA) GetJustifiedNumberAndHash(chain consensus.ChainHeaderReader, headers []*types.Header) (uint64, common.Hash, error) { diff --git a/eth/api_miner.go b/eth/api_miner.go index 802c8f0b44..f187cf7c4d 100644 --- a/eth/api_miner.go +++ b/eth/api_miner.go @@ -133,6 +133,11 @@ func (api *MinerAPI) SetDoubleSign(on bool) miner.MBConfig { return api.e.Miner().MBConfig() } +func (api *MinerAPI) SetVoteDisable(on bool) miner.MBConfig { + api.e.Miner().SetVoteDisable(on) + return api.e.Miner().MBConfig() +} + func (api *MinerAPI) SetSkipOffsetInturn(offset uint64) miner.MBConfig { api.e.Miner().SetSkipOffsetInturn(offset) return api.e.Miner().MBConfig() diff --git a/eth/backend.go b/eth/backend.go index 0d434a9130..686a2b3460 100644 --- a/eth/backend.go +++ b/eth/backend.go @@ -621,6 +621,7 @@ func (s *Ethereum) StopMining() { } func (s *Ethereum) IsMining() bool { return s.miner.Mining() } +func (s *Ethereum) VoteEnabled() bool { return s.miner.VoteEnabled() } func (s *Ethereum) Miner() *miner.Miner { return s.miner } func (s *Ethereum) AccountManager() *accounts.Manager { return s.accountManager } diff --git a/miner/gen_mb_config.go b/miner/gen_mb_config.go index cd2c8158b6..32e2a1464f 100644 --- a/miner/gen_mb_config.go +++ b/miner/gen_mb_config.go @@ -6,12 +6,14 @@ package miner func (m MBConfig) MarshalTOML() (interface{}, error) { type MBConfig struct { DoubleSign bool + VoteDisable bool SkipOffsetInturn *uint64 `toml:",omitempty"` BroadcastDelayBlocks uint64 LastBlockMiningTime uint64 } var enc MBConfig enc.DoubleSign = m.DoubleSign + enc.VoteDisable = m.VoteDisable enc.SkipOffsetInturn = m.SkipOffsetInturn enc.BroadcastDelayBlocks = m.BroadcastDelayBlocks enc.LastBlockMiningTime = m.LastBlockMiningTime @@ -22,6 +24,7 @@ func (m MBConfig) MarshalTOML() (interface{}, error) { func (m *MBConfig) UnmarshalTOML(unmarshal func(interface{}) error) error { type MBConfig struct { DoubleSign *bool + VoteDisable *bool SkipOffsetInturn *uint64 `toml:",omitempty"` BroadcastDelayBlocks *uint64 LastBlockMiningTime *uint64 @@ -33,6 +36,9 @@ func (m *MBConfig) UnmarshalTOML(unmarshal func(interface{}) error) error { if dec.DoubleSign != nil { m.DoubleSign = *dec.DoubleSign } + if dec.VoteDisable != nil { + m.VoteDisable = *dec.VoteDisable + } if dec.SkipOffsetInturn != nil { m.SkipOffsetInturn = dec.SkipOffsetInturn } diff --git a/miner/malicious_behaviour.go b/miner/malicious_behaviour.go index 0fb7e4fc8f..13aad5542b 100644 --- a/miner/malicious_behaviour.go +++ b/miner/malicious_behaviour.go @@ -4,6 +4,8 @@ package miner type MBConfig struct { // Generate two consecutive blocks for the same parent block DoubleSign bool + // Disable voting for Fast Finality + VoteDisable bool // Skip block production for in-turn validators at a specified offset SkipOffsetInturn *uint64 `toml:",omitempty"` // Delay broadcasting mined blocks by a specified number of blocks, only for in turn validators @@ -14,6 +16,7 @@ type MBConfig struct { var DefaultMBConfig = MBConfig{ DoubleSign: false, + VoteDisable: false, BroadcastDelayBlocks: 0, LastBlockMiningTime: 0, } diff --git a/miner/miner.go b/miner/miner.go index 8bdc68a6f8..d40dcc9c21 100644 --- a/miner/miner.go +++ b/miner/miner.go @@ -204,6 +204,10 @@ func (miner *Miner) Mining() bool { return miner.worker.isRunning() } +func (miner *Miner) VoteEnabled() bool { + return miner.worker.config.VoteEnable && !miner.worker.config.MB.VoteDisable +} + func (miner *Miner) InTurn() bool { return miner.worker.inTurn() } @@ -299,6 +303,10 @@ func (miner *Miner) SetDoubleSign(on bool) { miner.worker.config.MB.DoubleSign = on } +func (miner *Miner) SetVoteDisable(on bool) { + miner.worker.config.MB.VoteDisable = on +} + func (miner *Miner) SetSkipOffsetInturn(offset uint64) { miner.worker.config.MB.SkipOffsetInturn = &offset } From 6f4f4046ffa69aa186ce7db8c68d7690ae693ef2 Mon Sep 17 00:00:00 2001 From: NathanBSC Date: Wed, 14 Aug 2024 15:41:49 +0800 Subject: [PATCH 40/41] miner: fix BlobSidecar.BlockHash for double signed blocks --- core/types/block.go | 9 +++++++++ core/vote/vote_pool_test.go | 2 +- eth/backend.go | 2 +- miner/worker.go | 10 +++++++--- 4 files changed, 18 insertions(+), 5 deletions(-) diff --git a/core/types/block.go b/core/types/block.go index c7619f3f76..c0fd3e8a7e 100644 --- a/core/types/block.go +++ b/core/types/block.go @@ -19,6 +19,7 @@ package types import ( "encoding/binary" + "encoding/json" "fmt" "io" "math/big" @@ -551,6 +552,14 @@ func (b *Block) WithSidecars(sidecars BlobSidecars) *Block { return block } +func (b *Block) DeepCopySidecars(sidecars BlobSidecars) { + b.sidecars = make(BlobSidecars, len(sidecars)) + if len(sidecars) != 0 { + buffer, _ := json.Marshal(sidecars) + json.Unmarshal(buffer, &b.sidecars) + } +} + // Hash returns the keccak256 hash of b's header. // The hash is computed on the first call and cached thereafter. func (b *Block) Hash() common.Hash { diff --git a/core/vote/vote_pool_test.go b/core/vote/vote_pool_test.go index 68ee4e8ae7..4ccc2f0bae 100644 --- a/core/vote/vote_pool_test.go +++ b/core/vote/vote_pool_test.go @@ -77,7 +77,7 @@ func newTestBackend() *testBackend { return &testBackend{eventMux: new(event.TypeMux)} } func (b *testBackend) IsMining() bool { return true } -func (b *testBackend) VoteEnabled() bool { return true } +func (b *testBackend) VoteEnabled() bool { return true } func (b *testBackend) EventMux() *event.TypeMux { return b.eventMux } func (p *mockPOSA) GetJustifiedNumberAndHash(chain consensus.ChainHeaderReader, headers []*types.Header) (uint64, common.Hash, error) { diff --git a/eth/backend.go b/eth/backend.go index 686a2b3460..c0e41b1fcd 100644 --- a/eth/backend.go +++ b/eth/backend.go @@ -621,7 +621,7 @@ func (s *Ethereum) StopMining() { } func (s *Ethereum) IsMining() bool { return s.miner.Mining() } -func (s *Ethereum) VoteEnabled() bool { return s.miner.VoteEnabled() } +func (s *Ethereum) VoteEnabled() bool { return s.miner.VoteEnabled() } func (s *Ethereum) Miner() *miner.Miner { return s.miner } func (s *Ethereum) AccountManager() *accounts.Manager { return s.accountManager } diff --git a/miner/worker.go b/miner/worker.go index df83f8e0d6..e67f230e2a 100644 --- a/miner/worker.go +++ b/miner/worker.go @@ -699,7 +699,8 @@ func (w *worker) resultLoop() { shadowHeader := block.Header() shadowHeader.Extra[0] = 'd' shadowHeader.Extra[1] = 's' - shadowBlock := types.NewBlockWithHeader(shadowHeader).WithBody(block.Transactions(), block.Uncles()).WithWithdrawals(block.Withdrawals()).WithSidecars(block.Sidecars()) + shadowBlock := types.NewBlockWithHeader(shadowHeader).WithBody(block.Transactions(), block.Uncles()).WithWithdrawals(block.Withdrawals()) + shadowBlock.DeepCopySidecars(block.Sidecars()) shadowBlock, err := p.AssembleSignature(shadowBlock) if err == nil { w.postBlock(shadowBlock, inturn) @@ -707,6 +708,9 @@ func (w *worker) resultLoop() { hash := shadowBlock.Hash() log.Info("Successfully sealed new block", "number", shadowBlock.Number(), "sealhash", sealhash, "hash", hash, "elapsed", common.PrettyDuration(time.Since(task.createdAt))) + if len(block.Sidecars()) != 0 { + log.Debug("show sidecars", "block.Sidecars()[0].BlockHash", block.Sidecars()[0].BlockHash, "shadowBlock.Sidecars()[0].BlockHash", shadowBlock.Sidecars()[0].BlockHash) + } } else { log.Info("Failed to AssembleSignature", "err", err) } @@ -1348,8 +1352,8 @@ LOOP: workList = append(workList, work) delay := w.engine.Delay(w.chain, work.header, &w.config.DelayLeftOver) - if w.config.MB.LastBlockMiningTime > w.chainConfig.Parlia.Period*1000/2 { - if p, ok := w.engine.(*parlia.Parlia); ok { + if p, ok := w.engine.(*parlia.Parlia); ok { + if w.config.MB.LastBlockMiningTime > w.chainConfig.Parlia.Period*1000/2 { service := p.APIs(w.chain)[0].Service latestBlockNumber := rpc.LatestBlockNumber currentTurnLength, err := service.(*parlia.API).GetTurnLength(&latestBlockNumber) From c0130a6b0b0e42369ae3b392dbb3d0ed95cb6700 Mon Sep 17 00:00:00 2001 From: NathanBSC Date: Tue, 20 Aug 2024 15:41:44 +0800 Subject: [PATCH 41/41] consensus/parlia: add debug log for backOffTime --- consensus/parlia/parlia.go | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/consensus/parlia/parlia.go b/consensus/parlia/parlia.go index 8a8b4aca83..b52469f025 100644 --- a/consensus/parlia/parlia.go +++ b/consensus/parlia/parlia.go @@ -2124,6 +2124,10 @@ func (p *Parlia) backOffTime(snap *Snapshot, header *types.Header, val common.Ad backOffSteps[i], backOffSteps[j] = backOffSteps[j], backOffSteps[i] }) + for i := uint64(0); i < uint64(n); i++ { + log.Debug("backOffTime", "Number", header.Number, "val", validators[i], "delay", delay+backOffSteps[i]*wiggleTime) + } + delay += backOffSteps[idx] * wiggleTime return delay }