Compare commits

..

94 Commits

Author SHA1 Message Date
joeycli
facbe6a886 chore: add mgasps metrics 2024-08-29 20:35:58 +08:00
joeycli
84da730eed chore: add pprof service 2024-08-29 20:35:36 +08:00
joeycli
85a6b17ab0 chore: add reopen same tree error debug info 2024-08-22 15:05:42 +08:00
joeycli
8db789b2c0 fix: update trie error 2024-08-22 14:14:29 +08:00
joeycli
36044b05f3 chore: add open state version 2024-08-21 16:39:28 +08:00
joeycli
d5e38ad81e chore: adjust log confidition 2024-08-21 14:23:51 +08:00
joeycli
d5a438a06d chore: add diff and disk version log 2024-08-20 18:02:45 +08:00
Fynn
b585984e32 fix: remove enable hash check 2024-08-20 11:23:26 +08:00
joeycli
a1d4b06707 feat: check ca changeable 2024-08-20 09:01:18 +08:00
joeycli
ea76d5f359 chore: add debug inof for get trie version mismatch error 2024-08-20 08:24:57 +08:00
joeycli
b8fa4761b8 fix: get ca trie 2024-08-20 08:02:58 +08:00
joeycli
3ad7c4e63b fix: panic for updating code 2024-08-20 07:44:17 +08:00
joeycli
74ab9ab248 fix: changte the confidition for open storage tree 2024-08-20 07:38:00 +08:00
joeycli
9c239db9d9 fix: compare func 2024-08-19 16:52:42 +08:00
joeycli
d3854b41ec fix: compare funx 2024-08-19 16:51:13 +08:00
joeycli
30b371daf2 chore: compatable empty hash 2024-08-19 16:45:22 +08:00
joeycli
4764fdb47f fix: the timing release debug state instance 2024-08-19 16:23:01 +08:00
joeycli
fa7a43a2df fix: add calc hash point 2024-08-19 16:14:14 +08:00
joeycli
1a40f79ade fix: set path mode breakpoint 2024-08-19 16:08:56 +08:00
joeycli
3ad4700907 fix: diff debug state error 2024-08-19 16:04:41 +08:00
joeycli
f724941948 fix: add protection for debug hash state 2024-08-19 15:33:06 +08:00
joeycli
ef3f9dfaa7 fix: repeated cmd error 2024-08-19 15:11:27 +08:00
joeycli
aa9d5182c1 fix: panic bug 2024-08-19 15:05:55 +08:00
joeycli
a0daf107f9 fix: genesis init panic 2024-08-19 14:58:54 +08:00
joeycli
55cdcfaff3 fix: repeat cmd error 2024-08-19 14:52:06 +08:00
joeycli
7d5e6ce2d7 feat: add version and hash state diff system 2024-08-19 14:08:40 +08:00
joeycli
1cbdf0a4c9 feat: add hash state db debug system 2024-08-19 12:55:24 +08:00
joeycli
997d7b5bba chore: delete debug log 2024-08-18 16:50:32 +08:00
joeycli
90aa2e137c fix: change pebble to default db 2024-08-18 16:45:25 +08:00
joeycli
e940e28f6c fix: access nil pointer 2024-08-18 16:39:25 +08:00
joeycli
23c60a38a4 feat: add version state debug system 2024-08-18 16:21:06 +08:00
joeycli
f67f494346 chore: add 373559 debug breakpoint 2024-08-16 22:28:44 +08:00
joeycli
84767d1957 chore: add update storage debug info 2024-08-16 21:17:28 +08:00
joeycli
bf808915f0 chore: add update storage debug info 2024-08-16 21:10:46 +08:00
joeycli
b80d78701a chore: add update storage debug info 2024-08-16 21:04:43 +08:00
joeycli
3c4b452ee2 fix: chang condition for ca 2024-08-16 20:45:37 +08:00
joeycli
8197064e91 fix: chang condition for ca 2024-08-16 20:30:18 +08:00
joeycli
90de1d7ff8 fix: version mismatch that add contract balance without update storage tree 2024-08-16 20:16:01 +08:00
joeycli
77dea68afd chore: add detete key debug log 2024-08-16 16:51:10 +08:00
joeycli
9d20658f8d chore: debug 24611 2024-08-16 14:59:57 +08:00
joeycli
dc510033c0 feat: return version for repeat search account tree 2024-08-16 14:43:23 +08:00
joeycli
7bce07abdf chore: adjust state reset 2024-08-16 14:08:55 +08:00
joeycli
2e4ec39e52 chore: add owner and hash log 2024-08-15 17:26:40 +08:00
joeycli
0a901183b9 chore: delete part log 2024-08-15 16:53:16 +08:00
joeycli
2e38d0662c chore: change panic to log error 2024-08-15 16:09:37 +08:00
joeycli
ac2d1a8ada chore: add versa db error log 2024-08-15 15:46:22 +08:00
joeycli
c6d8d6355d fix: get code error 2024-08-15 15:13:21 +08:00
joeycli
7462078caa chore: add system tx log 2024-08-15 14:47:54 +08:00
joeycli
cf04af0cc1 chore: add tx execute log 2024-08-15 14:25:34 +08:00
joeycli
dec27d1b52 fix: add address check for get versa tree 2024-08-15 12:06:24 +08:00
joeycli
bbef39738d chore:add tree get debug info 2024-08-15 09:54:18 +08:00
joeycli
6dfcbc6519 fix lint error 2024-08-14 17:10:35 +08:00
joeycli
42b72feed1 chore: add debug state after tx execute 2024-08-14 16:49:02 +08:00
joeycli
8d7ee3aeb6 chore: add parse state obj 2024-08-14 16:32:58 +08:00
joeycli
a3f8c707e6 chore: fix build error 2024-08-14 16:05:21 +08:00
joeycli
bd9c2ae465 chore: add tx hash log 2024-08-14 16:03:14 +08:00
joeycli
023b092e95 chore: delete storage pool 2024-08-14 15:35:04 +08:00
joeycli
0941eb6ccf chore: panic for snap 2024-08-14 15:21:05 +08:00
joeycli
b73a98cd65 chore: forbid prefetcher 2024-08-14 15:02:20 +08:00
joeycli
26d7f62caa chore: forbid prefetcher 2024-08-14 15:00:33 +08:00
joeycli
be0a305251 chore: add delete obj debug info 2024-08-14 14:46:51 +08:00
joeycli
bfe07c5a83 chore: adjust state obj debug info 2024-08-14 14:33:31 +08:00
joeycli
412c5ee791 chore: add state obj debug info 2024-08-14 12:03:27 +08:00
joeycli
3a70b35ea2 chore: dadd debug log for tx diff 2024-08-14 11:10:51 +08:00
joeycli
f284358f8f chore: delete redundant code 2024-08-14 09:32:57 +08:00
joeycli
5b4e00c905 fix: decode storage val 2024-08-13 20:35:17 +08:00
joeycli
c572535693 chore: add reset panic 2024-08-13 20:25:33 +08:00
joeycli
324e4a4af7 chore: add panic log 2024-08-13 20:07:17 +08:00
joeycli
58dabc990e chore: add apply tx debug log 2024-08-13 20:03:20 +08:00
joeycli
2f0f91dbf8 chore: delete debug log 2024-08-13 18:21:32 +08:00
joeycli
657eced3b7 chore: delete panic code 2024-08-13 18:02:33 +08:00
joeycli
f69ff95e77 fix: blockchain stateat use rw state 2024-08-13 17:54:37 +08:00
joeycli
04e5c1732c chore: add debug panic 2024-08-13 17:36:18 +08:00
joeycli
ec2384aca4 fix: change check from tree root to tree handler 2024-08-13 17:06:23 +08:00
joeycli
83287cec5c chore: add debug log 2024-08-13 16:22:41 +08:00
joeycli
d162a63438 chore: change panic to log 2024-08-13 15:35:02 +08:00
joeycli
b00582cb8a chore: add state info debug log 2024-08-13 15:10:16 +08:00
joeycli
d8c3726154 fix: state object trie expire 2024-08-13 14:26:36 +08:00
joeycli
e8309adedc chore: delete debug print code 2024-08-13 11:05:17 +08:00
joeycli
ed7aa3e3b9 fix: storage tree value encode 2024-08-13 10:57:42 +08:00
joeycli
6188aaec48 chore: add debug print statedb 2024-08-13 10:20:08 +08:00
joeycli
60df2fa712 fix: open strorage trie param error 2024-08-13 08:53:12 +08:00
joeycli
bb167a9af6 chore: add stack debug 2024-08-12 19:35:26 +08:00
joeycli
66bd59013f chore: delete debug code and add log 2024-08-12 18:20:27 +08:00
joeycli
6b7c807e86 chore: add debug code 2024-08-12 18:15:32 +08:00
joeycli
3a34c737dc feat: support has state on statedb and must fullsync under version 2024-08-12 17:58:22 +08:00
joeycli
4635a457c1 feat: add caching db and trie copy 2024-08-12 17:30:21 +08:00
joeycli
e1a2b8e8d6 feat: init genesis 2024-08-12 16:00:06 +08:00
joeycli
6cf5169ce1 feat: add version scheme for startup 2024-08-12 11:46:32 +08:00
joeycli
7f3aac35e4 feat: add mode for new caching db 2024-08-12 11:07:45 +08:00
joeycli
435410f6f3 chore: forbid versiondb rewind 2024-08-12 10:50:49 +08:00
joeycli
d2e5c03965 feat: add version commit 2024-08-12 10:35:13 +08:00
joeycli
41ab497c22 feat: setup versa db 2024-08-09 17:29:47 +08:00
zzzckck
83a9b13771 Merge pull request #2607 from NathanBSC/for_release_v1.4.12
Revert "miner/worker: broadcast block immediately once sealed (bnb-chain#2576)"
2024-07-24 12:07:13 +08:00
101 changed files with 2628 additions and 2673 deletions

View File

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

View File

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

View File

@@ -1,48 +1,4 @@
# Changelog
## v1.4.14
### BUGFIX
* [\#2643](https://github.com/bnb-chain/bsc/pull/2643)core: fix cache for receipts
* [\#2656](https://github.com/bnb-chain/bsc/pull/2656)ethclient: fix BlobSidecars api
* [\#2657](https://github.com/bnb-chain/bsc/pull/2657)fix: update prunefreezers offset when pruneancient and the dataset has pruned block
### FEATURE
* [\#2661](https://github.com/bnb-chain/bsc/pull/2661)config: setup Mainnet 2 hardfork date: HaberFix & Bohr
### IMPROVEMENT
* [\#2578](https://github.com/bnb-chain/bsc/pull/2578)core/systemcontracts: use vm.StateDB in UpgradeBuildInSystemContract
* [\#2649](https://github.com/bnb-chain/bsc/pull/2649)internal/debug: remove memsize
* [\#2655](https://github.com/bnb-chain/bsc/pull/2655)internal/ethapi: make GetFinalizedHeader monotonically increasing
* [\#2658](https://github.com/bnb-chain/bsc/pull/2658)core: improve readability of the fork choice logic
* [\#2665](https://github.com/bnb-chain/bsc/pull/2665)faucet: bump and resend faucet transaction if it has been pending for a while
## v1.4.13
### BUGFIX
* [\#2602](https://github.com/bnb-chain/bsc/pull/2602) fix: prune-state when specify --triesInMemory 32
* [\#2579](https://github.com/bnb-chain/bsc/pull/00025790) fix: only take non-mempool tx to calculate bid price
### FEATURE
* [\#2634](https://github.com/bnb-chain/bsc/pull/2634) config: setup Testnet Bohr hardfork date
* [\#2482](https://github.com/bnb-chain/bsc/pull/2482) BEP-341: Validators can produce consecutive blocks
* [\#2502](https://github.com/bnb-chain/bsc/pull/2502) BEP-402: Complete Missing Fields in Block Header to Generate Signature
* [\#2558](https://github.com/bnb-chain/bsc/pull/2558) BEP-404: Clear Miner History when Switching Validators Set
* [\#2605](https://github.com/bnb-chain/bsc/pull/2605) feat: add bohr upgrade contracts bytecode
* [\#2614](https://github.com/bnb-chain/bsc/pull/2614) fix: update stakehub bytecode after zero address agent issue fixed
* [\#2608](https://github.com/bnb-chain/bsc/pull/2608) consensus/parlia: modify mining time for last block in one turn
* [\#2618](https://github.com/bnb-chain/bsc/pull/2618) consensus/parlia: exclude inturn validator when calculate backoffTime
* [\#2621](https://github.com/bnb-chain/bsc/pull/2621) core: not record zero hash beacon block root with Parlia engine
### IMPROVEMENT
* [\#2589](https://github.com/bnb-chain/bsc/pull/2589) core/vote: vote before committing state and writing block
* [\#2596](https://github.com/bnb-chain/bsc/pull/2596) core: improve the network stability when double sign happens
* [\#2600](https://github.com/bnb-chain/bsc/pull/2600) core: cache block after wroten into db
* [\#2629](https://github.com/bnb-chain/bsc/pull/2629) utils: add GetTopAddr to analyse large traffic
* [\#2591](https://github.com/bnb-chain/bsc/pull/2591) consensus/parlia: add GetJustifiedNumber and GetFinalizedNumber
* [\#2611](https://github.com/bnb-chain/bsc/pull/2611) cmd/utils: add new flag OverridePassedForkTime
* [\#2603](https://github.com/bnb-chain/bsc/pull/2603) faucet: rate limit initial implementation
* [\#2622](https://github.com/bnb-chain/bsc/pull/2622) tests: fix evm-test CI
* [\#2628](https://github.com/bnb-chain/bsc/pull/2628) Makefile: use docker compose v2 instead of v1
## v1.4.12
@@ -79,6 +35,7 @@
* [\#2534](https://github.com/bnb-chain/bsc/pull/2534) fix: nil pointer when clear simulating bid
* [\#2535](https://github.com/bnb-chain/bsc/pull/2535) upgrade: add HaberFix hardfork
## v1.4.10
### FEATURE
NA

View File

@@ -17,11 +17,6 @@ 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
@@ -34,11 +29,11 @@ truffle-test:
docker build . -f ./docker/Dockerfile --target bsc-genesis -t bsc-genesis
docker build . -f ./docker/Dockerfile --target bsc -t bsc
docker build . -f ./docker/Dockerfile.truffle -t truffle-test
docker compose -f ./tests/truffle/docker-compose.yml up genesis
docker compose -f ./tests/truffle/docker-compose.yml up -d bsc-rpc bsc-validator1
docker-compose -f ./tests/truffle/docker-compose.yml up genesis
docker-compose -f ./tests/truffle/docker-compose.yml up -d bsc-rpc bsc-validator1
sleep 30
docker compose -f ./tests/truffle/docker-compose.yml up --exit-code-from truffle-test truffle-test
docker compose -f ./tests/truffle/docker-compose.yml down
docker-compose -f ./tests/truffle/docker-compose.yml up --exit-code-from truffle-test truffle-test
docker-compose -f ./tests/truffle/docker-compose.yml down
#? lint: Run certain pre-selected linters
lint: ## Run linters.

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@@ -43,42 +43,7 @@ func TestExtraParse(t *testing.T) {
}
}
// case 3, |---Extra Vanity---|---Validators Number and Validators Bytes---|---Turn Length---|---Empty---|---Extra Seal---|
{
extraData := "0xd983010209846765746889676f312e31392e3131856c696e75780000a6bf97c1152465176c461afb316ebc773c61faee85a6515daa8a923564c6ffd37fb2fe9f118ef88092e8762c7addb526ab7eb1e772baef85181f892c731be0c1891a50e6b06262c816295e26495cef6f69dfa69911d9d8e4f3bbadb89b977cf58294f7239d515e15b24cfeb82494056cf691eaf729b165f32c9757c429dba5051155903067e56ebe3698678e912d4c407bbe49438ed859fe965b140dcf1aab71a993c1f7f6929d1fe2a17b4e14614ef9fc5bdc713d6631d675403fbeefac55611bf612700b1b65f4744861b80b0f7d6ab03f349bbafec1551819b8be1efea2fc46ca749aa184248a459464eec1a21e7fc7b71a053d9644e9bb8da4853b8f872cd7c1d6b324bf1922829830646ceadfb658d3de009a61dd481a114a2e761c554b641742c973867899d300000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000069c77a677c40c7fbea129d4b171a39b7a8ddabfab2317f59d86abfaf690850223d90e9e7593d91a29331dfc2f84d5adecc75fc39ecab4632c1b4400a3dd1e1298835bcca70f657164e5b75689b64b7fd1fa275f334f28e1896a26afa1295da81418593bd12814463d9f6e45c36a0e47eb4cd3e5b6af29c41e2a3a5636430155a466e216585af3ba772b61c6014342d914470ec7ac2975be345796c2b81db0422a5fd08e40db1fc2368d2245e4b18b1d0b85c921aaaafd2e341760e29fc613edd39f71254614e2055c3287a517ae2f5b9e386cd1b50a4550696d957cb4900f03ab84f83ff2df44193496793b847f64e9d6db1b3953682bb95edd096eb1e69bbd357c200992ca78050d0cbe180cfaa018e8b6c8fd93d6f4cea42bbb345dbc6f0dfdb5bec73a8a257074e82b881cfa06ef3eb4efeca060c2531359abd0eab8af1e3edfa2025fca464ac9c3fd123f6c24a0d78869485a6f79b60359f141df90a0c745125b131caaffd12000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000b218c5d6af1f979ac42bc68d98a5a0d796c6ab01000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000b4dd66d7c2c7e57f628210187192fb89d4b99dd4000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000be807dddb074639cd9fa61b47676c064fc50d62cb1f2c71577def3144fabeb75a8a1c8cb5b51d1d1b4a05eec67988b8685008baa17459ec425dbaebc852f496dc92196cdcc8e6d00c17eb431350c6c50d8b8f05176b90b11b3a3d4feb825ae9702711566df5dbf38e82add4dd1b573b95d2466fa6501ccb81e9d26a352b96150ccbf7b697fd0a419d1d6bf74282782b0b3eb1413c901d6ecf02e8e28000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000e2d3a739effcd3a99387d015e260eefac72ebea1956c470ddff48cb49300200b5f83497f3a3ccb3aeb83c5edd9818569038e61d197184f4aa6939ea5e9911e3e98ac6d21e9ae3261a475a27bb1028f140bc2a7c843318afd000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000ea0a6e3c511bbd10f4519ece37dc24887e11b55db2d4c6283c44a1c7bd503aaba7666e9f0c830e0ff016c1c750a5e48757a713d0836b1cabfd5c281b1de3b77d1c192183ee226379db83cffc681495730c11fdde79ba4c0c000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000ef0274e31810c9df02f98fafde0f841f4e66a1cd00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000004e99f701bb14cb7dfb68b90bd3e6d1ca656964630de71beffc7f33f7f08ec99d336ec51ad9fad0ac84ae77ca2e8ad9512acc56e0d7c93f3c2ce7de1b69149a5a400"
extra, err := parseExtra(extraData)
assert.NoError(t, err)
{
var have = extra.ValidatorSize
var want = uint8(21)
if have != want {
t.Fatalf("extra.ValidatorSize mismatch, have %d, want %d", have, want)
}
}
{
var have = common.Bytes2Hex(extra.Validators[14].Address[:])
var want = "cc8e6d00c17eb431350c6c50d8b8f05176b90b11"
if have != want {
t.Fatalf("extra.Validators[14].Address mismatch, have %s, want %s", have, want)
}
}
{
var have = common.Bytes2Hex(extra.Validators[18].BLSPublicKey[:])
var want = "b2d4c6283c44a1c7bd503aaba7666e9f0c830e0ff016c1c750a5e48757a713d0836b1cabfd5c281b1de3b77d1c192183"
if have != want {
t.Fatalf("extra.Validators[18].BLSPublicKey mismatch, have %s, want %s", have, want)
}
}
{
var have = extra.TurnLength
var want = uint8(4)
if *have != want {
t.Fatalf("extra.TurnLength mismatch, have %d, want %d", *have, want)
}
}
}
// case 4, |---Extra Vanity---|---Empty---|---Vote Attestation---|---Extra Seal---|
// case 3, |---Extra Vanity---|---Empty---|---Vote Attestation---|---Extra Seal---|
{
extraData := "0xd883010205846765746888676f312e32302e35856c696e75780000002995c52af8b5830563efb86089cf168dcf4c5d3cb057926628ad1bf0f03ea67eef1458485578a4f8489afa8a853ecc7af45e2d145c21b70641c4b29f0febd2dd2c61fa1ba174be3fd47f1f5fa2ab9b5c318563d8b70ca58d0d51e79ee32b2fb721649e2cb9d36538361fba11f84c8401d14bb7a0fa67ddb3ba654d6006bf788710032247aa4d1be0707273e696b422b3ff72e9798401d14bbaa01225f505f5a0e1aefadcd2913b7aac9009fe4fb3d1bf57399e0b9dce5947f94280fe6d3647276c4127f437af59eb7c7985b2ae1ebe432619860695cb6106b80cc66c735bc1709afd11f233a2c97409d38ebaf7178aa53e895aea2fe0a229f71ec601"
extra, err := parseExtra(extraData)
@@ -99,9 +64,9 @@ func TestExtraParse(t *testing.T) {
}
}
// case 5, |---Extra Vanity---|---Validators Number and Validators Bytes---|---Vote Attestation---|---Extra Seal---|
// case 4, |---Extra Vanity---|---Validators Number and Validators Bytes---|---Vote Attestation---|---Extra Seal---|
{
extraData := "0xd883010209846765746888676f312e31392e38856c696e7578000000dc55905c071284214b9b9c85549ab3d2b972df0deef66ac2c98e82934ca974fdcd97f3309de967d3c9c43fa711a8d673af5d75465844bf8969c8d1948d903748ac7b8b1720fa64e50c35552c16704d214347f29fa77f77da6d75d7c752b742ad4855bae330426b823e742da31f816cc83bc16d69a9134be0cfb4a1d17ec34f1b5b32d5c20440b8536b1e88f0f247788386d0ed6c748e03a53160b4b30ed3748cc5000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000980a75ecd1309ea12fa2ed87a8744fbfc9b863d589037a9ace3b590165ea1c0c5ac72bf600b7c88c1e435f41932c1132aae1bfa0bb68e46b96ccb12c3415e4d82af717d8a2959d3f95eae5dc7d70144ce1b73b403b7eb6e0b973c2d38487e58fd6e145491b110080fb14ac915a0411fc78f19e09a399ddee0d20c63a75d8f930f1694544ad2dc01bb71b214cb885500844365e95cd9942c7276e7fd8a2750ec6dded3dcdc2f351782310b0eadc077db59abca0f0cd26776e2e7acb9f3bce40b1fa5221fd1561226c6263cc5ff474cf03cceff28abc65c9cbae594f725c80e12d96c9b86c3400e529bfe184056e257c07940bb664636f689e8d2027c834681f8f878b73445261034e946bb2d901b4b878f8b27bb8608c11016739b3f8a19e54ab8c7abacd936cfeba200f3645a98b65adb0dd3692b69ce0b3ae10e7176b9a4b0d83f04065b1042b4bcb646a34b75c550f92fc34b8b2b1db0fa0d3172db23ba92727c80bcd306320d0ff411bf858525fde13bc8e0370f84c8401e9c2e6a0820dc11d63176a0eb1b828bc5376867b275579112b7013358da40317e7bab6e98401e9c2e7a00edc71ce80105a3220a87bea2792fa340d66c59002f02b0a09349ed1ed28407080048b972fac2b9077a4dcb6fc37093799a652858016c99142b227500c844fa97ec22e3f9d3b1e982f14bcd999a7453e89ce5ef5c55f1c7f8f74ba904186cd67828200"
extraData := "0xd883010209846765746888676f312e31392e38856c696e7578000000dc55905c071284214b9b9c85549ab3d2b972df0deef66ac2c98e82934ca974fdcd97f3309de967d3c9c43fa711a8d673af5d75465844bf8969c8d1948d903748ac7b8b1720fa64e50c35552c16704d214347f29fa77f77da6d75d7c752b742ad4855bae330426b823e742da31f816cc83bc16d69a9134be0cfb4a1d17ec34f1b5b32d5c20440b8536b1e88f0f247788386d0ed6c748e03a53160b4b30ed3748cc5000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000980a75ecd1309ea12fa2ed87a8744fbfc9b863d589037a9ace3b590165ea1c0c5ac72bf600b7c88c1e435f41932c1132aae1bfa0bb68e46b96ccb12c3415e4d82af717d8a2959d3f95eae5dc7d70144ce1b73b403b7eb6e0b973c2d38487e58fd6e145491b110080fb14ac915a0411fc78f19e09a399ddee0d20c63a75d8f930f1694544ad2dc01bb71b214cb885500844365e95cd9942c7276e7fd8a2750ec6dded3dcdc2f351782310b0eadc077db59abca0f0cd26776e2e7acb9f3bce40b1fa5221fd1561226c6263cc5ff474cf03cceff28abc65c9cbae594f725c80e12d96c9b86c3400e529bfe184056e257c07940bb664636f689e8d2027c834681f8f878b73445261034e946bb2d901b4b878f8b27bb8608c11016739b3f8a19e54ab8c7abacd936cfeba200f3645a98b65adb0dd3692b69ce0b3ae10e7176b9a4b0d83f04065b1042b4bcb646a34b75c550f92fc34b8b2b1db0fa0d3172db23ba92727c80bcd306320d0ff411bf858525fde13bc8e0370f84c8401e9c2e6a0820dc11d63176a0eb1b828bc5376867b275579112b7013358da40317e7bab6e98401e9c2e7a00edc71ce80105a3220a87bea2792fa340d66c59002f02b0a09349ed1ed284070808b972fac2b9077a4dcb6fc37093799a652858016c99142b227500c844fa97ec22e3f9d3b1e982f14bcd999a7453e89ce5ef5c55f1c7f8f74ba904186cd67828200"
extra, err := parseExtra(extraData)
assert.NoError(t, err)
{
@@ -140,53 +105,4 @@ func TestExtraParse(t *testing.T) {
}
}
}
// case 6, |---Extra Vanity---|---Validators Number and Validators Bytes---|---Turn Length---|---Vote Attestation---|---Extra Seal---|
{
extraData := "0xd883010209846765746888676f312e31392e38856c696e7578000000dc55905c071284214b9b9c85549ab3d2b972df0deef66ac2c98e82934ca974fdcd97f3309de967d3c9c43fa711a8d673af5d75465844bf8969c8d1948d903748ac7b8b1720fa64e50c35552c16704d214347f29fa77f77da6d75d7c752b742ad4855bae330426b823e742da31f816cc83bc16d69a9134be0cfb4a1d17ec34f1b5b32d5c20440b8536b1e88f0f247788386d0ed6c748e03a53160b4b30ed3748cc5000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000980a75ecd1309ea12fa2ed87a8744fbfc9b863d589037a9ace3b590165ea1c0c5ac72bf600b7c88c1e435f41932c1132aae1bfa0bb68e46b96ccb12c3415e4d82af717d8a2959d3f95eae5dc7d70144ce1b73b403b7eb6e0b973c2d38487e58fd6e145491b110080fb14ac915a0411fc78f19e09a399ddee0d20c63a75d8f930f1694544ad2dc01bb71b214cb885500844365e95cd9942c7276e7fd8a2750ec6dded3dcdc2f351782310b0eadc077db59abca0f0cd26776e2e7acb9f3bce40b1fa5221fd1561226c6263cc5ff474cf03cceff28abc65c9cbae594f725c80e12d96c9b86c3400e529bfe184056e257c07940bb664636f689e8d2027c834681f8f878b73445261034e946bb2d901b4b87804f8b27bb8608c11016739b3f8a19e54ab8c7abacd936cfeba200f3645a98b65adb0dd3692b69ce0b3ae10e7176b9a4b0d83f04065b1042b4bcb646a34b75c550f92fc34b8b2b1db0fa0d3172db23ba92727c80bcd306320d0ff411bf858525fde13bc8e0370f84c8401e9c2e6a0820dc11d63176a0eb1b828bc5376867b275579112b7013358da40317e7bab6e98401e9c2e7a00edc71ce80105a3220a87bea2792fa340d66c59002f02b0a09349ed1ed28407080048b972fac2b9077a4dcb6fc37093799a652858016c99142b227500c844fa97ec22e3f9d3b1e982f14bcd999a7453e89ce5ef5c55f1c7f8f74ba904186cd67828200"
extra, err := parseExtra(extraData)
assert.NoError(t, err)
{
var have = common.Bytes2Hex(extra.Validators[0].Address[:])
var want = "1284214b9b9c85549ab3d2b972df0deef66ac2c9"
if have != want {
t.Fatalf("extra.Validators[0].Address mismatch, have %s, want %s", have, want)
}
}
{
var have = common.Bytes2Hex(extra.Validators[0].BLSPublicKey[:])
var want = "8e82934ca974fdcd97f3309de967d3c9c43fa711a8d673af5d75465844bf8969c8d1948d903748ac7b8b1720fa64e50c"
if have != want {
t.Fatalf("extra.Validators[0].BLSPublicKey mismatch, have %s, want %s", have, want)
}
}
{
var have = extra.Validators[0].VoteIncluded
var want = true
if have != want {
t.Fatalf("extra.Validators[0].VoteIncluded mismatch, have %t, want %t", have, want)
}
}
{
var have = common.Bytes2Hex(extra.Data.TargetHash[:])
var want = "0edc71ce80105a3220a87bea2792fa340d66c59002f02b0a09349ed1ed284070"
if have != want {
t.Fatalf("extra.Data.TargetHash mismatch, have %s, want %s", have, want)
}
}
{
var have = extra.Data.TargetNumber
var want = uint64(32096999)
if have != want {
t.Fatalf("extra.Data.TargetNumber mismatch, have %d, want %d", have, want)
}
}
{
var have = extra.TurnLength
var want = uint8(4)
if *have != want {
t.Fatalf("extra.TurnLength mismatch, have %d, want %d", *have, want)
}
}
}
}

View File

@@ -24,7 +24,7 @@ const (
BLSPublicKeyLength = 48
// follow order in extra field
// |---Extra Vanity---|---Validators Number and Validators Bytes (or Empty)---|---Turn Length (or Empty)---|---Vote Attestation (or Empty)---|---Extra Seal---|
// |---Extra Vanity---|---Validators Number and Validators Bytes (or Empty)---|---Vote Attestation (or Empty)---|---Extra Seal---|
extraVanityLength = 32 // Fixed number of extra-data prefix bytes reserved for signer vanity
validatorNumberSize = 1 // Fixed number of extra prefix bytes reserved for validator number after Luban
validatorBytesLength = common.AddressLength + types.BLSPublicKeyLength
@@ -35,7 +35,6 @@ type Extra struct {
ExtraVanity string
ValidatorSize uint8
Validators validatorsAscending
TurnLength *uint8
*types.VoteAttestation
ExtraSeal []byte
}
@@ -114,15 +113,6 @@ func parseExtra(hexData string) (*Extra, error) {
sort.Sort(extra.Validators)
data = data[validatorBytesTotalLength-validatorNumberSize:]
dataLength = len(data)
// parse TurnLength
if dataLength > 0 {
if data[0] != '\xf8' {
extra.TurnLength = &data[0]
data = data[1:]
dataLength = len(data)
}
}
}
// parse Vote Attestation
@@ -158,10 +148,6 @@ func prettyExtra(extra Extra) {
}
}
if extra.TurnLength != nil {
fmt.Printf("TurnLength : %d\n", *extra.TurnLength)
}
if extra.VoteAttestation != nil {
fmt.Printf("Attestation :\n")
fmt.Printf("\tVoteAddressSet : %b, %d\n", extra.VoteAddressSet, bitset.From([]uint64{uint64(extra.VoteAddressSet)}).Count())

View File

@@ -49,14 +49,12 @@ import (
"github.com/ethereum/go-ethereum/log"
"github.com/ethereum/go-ethereum/params"
"github.com/gorilla/websocket"
"golang.org/x/time/rate"
)
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")
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")
@@ -78,12 +76,6 @@ var (
fixGasPrice = flag.Int64("faucet.fixedprice", 0, "Will use fixed gas price if specified")
twitterTokenFlag = flag.String("twitter.token", "", "Bearer token to authenticate with the v2 Twitter API")
twitterTokenV1Flag = flag.String("twitter.token.v1", "", "Bearer token to authenticate with the v1.1 Twitter API")
resendInterval = 15 * time.Second
resendBatchSize = 3
resendMaxGasPrice = big.NewInt(50 * params.GWei)
wsReadTimeout = 5 * time.Minute
minMainnetBalance = big.NewInt(2 * 1e6 * params.GWei) // 0.002 bnb
)
var (
@@ -94,17 +86,11 @@ 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), false)))
log.Info("faucet started")
log.SetDefault(log.NewLogger(log.NewTerminalHandlerWithLevel(os.Stderr, log.FromLegacyLevel(*logFlag), true)))
// Construct the payout tiers
amounts := make([]string, *tiersFlag)
for i := 0; i < *tiersFlag; i++ {
@@ -183,7 +169,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, *wsEndpointMainnet, ks, website.Bytes(), bep2eInfos)
faucet, err := newFaucet(genesis, *wsEndpoint, ks, website.Bytes(), bep2eInfos)
if err != nil {
log.Crit("Failed to start faucet", "err", err)
}
@@ -212,7 +198,6 @@ type bep2eInfo struct {
type faucet struct {
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
@@ -231,8 +216,6 @@ type faucet struct {
bep2eInfos map[string]bep2eInfo
bep2eAbi abi.ABI
limiter *IPRateLimiter
}
// wsConn wraps a websocket connection with a write mutex as the underlying
@@ -242,7 +225,7 @@ type wsConn struct {
wlock sync.Mutex
}
func newFaucet(genesis *core.Genesis, url string, mainnetUrl string, ks *keystore.KeyStore, index []byte, bep2eInfos map[string]bep2eInfo) (*faucet, error) {
func newFaucet(genesis *core.Genesis, url string, ks *keystore.KeyStore, index []byte, bep2eInfos map[string]bep2eInfo) (*faucet, error) {
bep2eAbi, err := abi.JSON(strings.NewReader(bep2eAbiJson))
if err != nil {
return nil, err
@@ -251,22 +234,10 @@ func newFaucet(genesis *core.Genesis, url string, mainnetUrl string, ks *keystor
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)
if err != nil {
return nil, err
}
return &faucet{
config: genesis.Config,
client: client,
clientMainnet: clientMainnet,
index: index,
keystore: ks,
account: ks.Accounts()[0],
@@ -274,7 +245,6 @@ func newFaucet(genesis *core.Genesis, url string, mainnetUrl string, ks *keystor
update: make(chan struct{}, 1),
bep2eInfos: bep2eInfos,
bep2eAbi: bep2eAbi,
limiter: limiter,
}, nil
}
@@ -302,20 +272,6 @@ func (f *faucet) webHandler(w http.ResponseWriter, r *http.Request) {
// apiHandler handles requests for Ether grants and transaction statuses.
func (f *faucet) apiHandler(w http.ResponseWriter, r *http.Request) {
ip := r.RemoteAddr
if len(r.Header.Get("X-Forwarded-For")) > 0 {
ips := strings.Split(r.Header.Get("X-Forwarded-For"), ",")
if len(ips) > 0 {
ip = strings.TrimSpace(ips[len(ips)-1])
}
}
if !f.limiter.GetLimiter(ip).Allow() {
log.Warn("Too many requests from client: ", "client", ip)
http.Error(w, "Too many requests", http.StatusTooManyRequests)
return
}
upgrader := websocket.Upgrader{CheckOrigin: func(r *http.Request) bool { return true }}
conn, err := upgrader.Upgrade(w, r, nil)
if err != nil {
@@ -398,11 +354,7 @@ func (f *faucet) apiHandler(w http.ResponseWriter, r *http.Request) {
Captcha string `json:"captcha"`
Symbol string `json:"symbol"`
}
// not sure if it helps or not, but set a read deadline could help prevent resource leakage
// if user did not give response for too long, then the routine will be stuck.
conn.SetReadDeadline(time.Now().Add(wsReadTimeout))
if err = conn.ReadJSON(&msg); err != nil {
log.Debug("read json message failed", "err", err, "ip", ip)
return
}
if !*noauthFlag && !strings.HasPrefix(msg.URL, "https://twitter.com/") && !strings.HasPrefix(msg.URL, "https://www.facebook.com/") {
@@ -420,9 +372,9 @@ func (f *faucet) apiHandler(w http.ResponseWriter, r *http.Request) {
}
continue
}
log.Info("Faucet funds requested", "url", msg.URL, "tier", msg.Tier, "ip", ip)
log.Info("Faucet funds requested", "url", msg.URL, "tier", msg.Tier)
// check #1: captcha verifications to exclude robot
// If captcha verifications are enabled, make sure we're not dealing with a robot
if *captchaToken != "" {
form := url.Values{}
form.Add("secret", *captchaSecret)
@@ -499,55 +451,24 @@ 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)
// check #2: check IP and ID(address) to ensure the user didn't request funds too recently,
// Ensure the user didn't request funds too recently
f.lock.Lock()
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
}
// check #3: minimum mainnet balance check, internal error will bypass the check to avoid blocking the faucet service
if f.clientMainnet != nil {
mainnetAddr := address
balanceMainnet, err := f.clientMainnet.BalanceAt(context.Background(), mainnetAddr, nil)
if err != nil {
log.Warn("check balance failed, call BalanceAt", "err", err)
} else if balanceMainnet == nil {
log.Warn("check balance failed, balanceMainnet is nil")
} else {
if balanceMainnet.Cmp(minMainnetBalance) < 0 {
f.lock.Unlock()
log.Warn("insufficient BNB on BSC mainnet", "address", mainnetAddr,
"balanceMainnet", balanceMainnet, "minMainnetBalance", minMainnetBalance)
// Send an error if failed to meet the minimum balance requirement
if err = sendError(wsconn, fmt.Errorf("insufficient BNB on BSC mainnet (require >=%sBNB)",
weiToEtherStringFx(minMainnetBalance, 3))); err != nil {
log.Warn("Failed to send mainnet minimum balance error to client", "err", err)
return
}
continue
}
}
}
log.Info("Faucet request valid", "url", msg.URL, "tier", msg.Tier, "user", username, "address", address, "ip", ip)
// now, it is ok to send tBNB or other tokens
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
@@ -595,12 +516,23 @@ func (f *faucet) apiHandler(w http.ResponseWriter, r *http.Request) {
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
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(timeoutInt64 - grace)
f.timeouts[ips[len(ips)-2]] = time.Now().Add(timeoutInt64 - grace)
f.timeouts[id] = time.Now().Add(timeout - grace)
f.timeouts[ips[len(ips)-2]] = time.Now().Add(timeout - grace)
fund = true
}
f.lock.Unlock()
// Send an error if too frequent funding, otherwise a success
if !fund {
if err = sendError(wsconn, fmt.Errorf("%s left until next allowance", common.PrettyDuration(time.Until(timeout)))); err != nil { // nolint: gosimple
log.Warn("Failed to send funding error to client", "err", err)
return
}
continue
}
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
@@ -649,52 +581,9 @@ 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 {
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())
if len(f.reqs) > 0 && f.reqs[0].Tx.Nonce() > f.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:]
}
@@ -736,7 +625,6 @@ func (f *faucet) loop() {
balance := new(big.Int).Div(f.balance, ether)
for _, conn := range f.conns {
go func(conn *wsConn) {
if err := send(conn, map[string]interface{}{
"funds": balance,
"funded": f.nonce,
@@ -744,14 +632,12 @@ func (f *faucet) loop() {
}, time.Second); err != nil {
log.Warn("Failed to send stats to client", "err", err)
conn.conn.Close()
return // Exit the goroutine if the first send fails
continue
}
if err := send(conn, head, time.Second); err != nil {
log.Warn("Failed to send header to client", "err", err)
conn.conn.Close()
}
}(conn)
}
f.lock.RUnlock()
}
@@ -770,12 +656,10 @@ func (f *faucet) loop() {
// Pending requests updated, stream to clients
f.lock.RLock()
for _, conn := range f.conns {
go func(conn *wsConn) {
if err := send(conn, map[string]interface{}{"requests": f.reqs}, time.Second); err != nil {
log.Warn("Failed to send requests to client", "err", err)
conn.conn.Close()
}
}(conn)
}
f.lock.RUnlock()
}

View File

@@ -1,44 +0,0 @@
package main
import (
lru "github.com/hashicorp/golang-lru"
"golang.org/x/time/rate"
)
type IPRateLimiter struct {
ips *lru.Cache // LRU cache to store IP addresses and their associated rate limiters
r rate.Limit // the rate limit, e.g., 5 requests per second
b int // the burst size, e.g., allowing a burst of 10 requests at once. The rate limiter gets into action
// only after this number exceeds
}
func NewIPRateLimiter(r rate.Limit, b int, size int) (*IPRateLimiter, error) {
cache, err := lru.New(size)
if err != nil {
return nil, err
}
i := &IPRateLimiter{
ips: cache,
r: r,
b: b,
}
return i, nil
}
func (i *IPRateLimiter) addIP(ip string) *rate.Limiter {
limiter := rate.NewLimiter(i.r, i.b)
i.ips.Add(ip, limiter)
return limiter
}
func (i *IPRateLimiter) GetLimiter(ip string) *rate.Limiter {
if limiter, exists := i.ips.Get(ip); exists {
return limiter.(*rate.Limiter)
}
return i.addIP(ip)
}

View File

@@ -62,7 +62,6 @@ var (
ArgsUsage: "<genesisPath>",
Flags: flags.Merge([]cli.Flag{
utils.CachePreimagesFlag,
utils.OverridePassedForkTime,
utils.OverrideBohr,
utils.OverrideVerkle,
utils.MultiDataBaseFlag,
@@ -254,10 +253,6 @@ func initGenesis(ctx *cli.Context) error {
defer stack.Close()
var overrides core.ChainOverrides
if ctx.IsSet(utils.OverridePassedForkTime.Name) {
v := ctx.Uint64(utils.OverridePassedForkTime.Name)
overrides.OverridePassedForkTime = &v
}
if ctx.IsSet(utils.OverrideBohr.Name) {
v := ctx.Uint64(utils.OverrideBohr.Name)
overrides.OverrideBohr = &v
@@ -838,7 +833,7 @@ func dump(ctx *cli.Context) error {
triedb := utils.MakeTrieDatabase(ctx, stack, db, true, true, false) // always enable preimage lookup
defer triedb.Close()
state, err := state.New(root, state.NewDatabaseWithNodeDB(db, triedb), nil)
state, err := state.New(root, state.NewDatabaseWithNodeDB(db, triedb, false), nil)
if err != nil {
return err
}

View File

@@ -33,7 +33,6 @@ 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"
@@ -97,7 +96,6 @@ type gethConfig struct {
Node node.Config
Ethstats ethstatsConfig
Metrics metrics.Config
FakeBeacon fakebeacon.Config
}
func loadConfig(file string, cfg *gethConfig) error {
@@ -187,10 +185,6 @@ func makeFullNode(ctx *cli.Context) (*node.Node, ethapi.Backend) {
params.RialtoGenesisHash = common.HexToHash(v)
}
if ctx.IsSet(utils.OverridePassedForkTime.Name) {
v := ctx.Uint64(utils.OverridePassedForkTime.Name)
cfg.Eth.OverridePassedForkTime = &v
}
if ctx.IsSet(utils.OverrideBohr.Name) {
v := ctx.Uint64(utils.OverrideBohr.Name)
cfg.Eth.OverrideBohr = &v
@@ -212,9 +206,6 @@ func makeFullNode(ctx *cli.Context) (*node.Node, ethapi.Backend) {
if ctx.IsSet(utils.OverrideBreatheBlockInterval.Name) {
params.BreatheBlockInterval = ctx.Uint64(utils.OverrideBreatheBlockInterval.Name)
}
if ctx.IsSet(utils.OverrideFixedTurnLength.Name) {
params.FixedTurnLength = ctx.Uint64(utils.OverrideFixedTurnLength.Name)
}
backend, eth := utils.RegisterEthService(stack, &cfg.Eth)
@@ -244,22 +235,11 @@ func makeFullNode(ctx *cli.Context) (*node.Node, ethapi.Backend) {
utils.RegisterEthStatsService(stack, backend, cfg.Ethstats.URL)
}
if ctx.IsSet(utils.FakeBeaconAddrFlag.Name) {
cfg.FakeBeacon.Addr = ctx.String(utils.FakeBeaconAddrFlag.Name)
}
if ctx.IsSet(utils.FakeBeaconPortFlag.Name) {
cfg.FakeBeacon.Port = ctx.Int(utils.FakeBeaconPortFlag.Name)
}
if cfg.FakeBeacon.Enable || ctx.IsSet(utils.FakeBeaconEnabledFlag.Name) {
go fakebeacon.NewService(&cfg.FakeBeacon, backend).Run()
}
git, _ := version.VCS()
utils.SetupMetrics(ctx,
utils.EnableBuildInfo(git.Commit, git.Date),
utils.EnableMinerInfo(ctx, &cfg.Eth.Miner),
utils.EnableNodeInfo(&cfg.Eth.TxPool, stack.Server().NodeInfo()),
utils.EnableNodeTrack(ctx, &cfg.Eth, stack),
)
return stack, backend
}

View File

@@ -18,6 +18,7 @@ package main
import (
"bytes"
"encoding/json"
"errors"
"fmt"
"math"
@@ -34,6 +35,7 @@ import (
"github.com/ethereum/go-ethereum/common/hexutil"
"github.com/ethereum/go-ethereum/console/prompt"
"github.com/ethereum/go-ethereum/core/rawdb"
"github.com/ethereum/go-ethereum/core/state"
"github.com/ethereum/go-ethereum/core/state/snapshot"
"github.com/ethereum/go-ethereum/crypto"
"github.com/ethereum/go-ethereum/ethdb"
@@ -91,6 +93,9 @@ Remove blockchain and state databases`,
dbHbss2PbssCmd,
dbTrieGetCmd,
dbTrieDeleteCmd,
getVersionDBState,
getHashDBState,
diffDebugStateDB,
},
}
dbInspectCmd = &cli.Command{
@@ -286,8 +291,141 @@ WARNING: This is a low-level operation which may cause database corruption!`,
Description: `This commands will read current offset from kvdb, which is the current offset and starting BlockNumber
of ancientStore, will also displays the reserved number of blocks in ancientStore `,
}
getVersionDBState = &cli.Command{
Action: getDebugVersionState,
Name: "get-debug-version-state",
Flags: []cli.Flag{
utils.VersionStateDirFlag,
utils.BlockNumber,
},
}
getHashDBState = &cli.Command{
Action: getDebugHashState,
Name: "get-debug-hash-state",
Flags: []cli.Flag{
utils.HashStateDirFlag,
utils.BlockNumber,
},
}
diffDebugStateDB = &cli.Command{
Action: diffDebugState,
Name: "diff-debug-state",
Flags: []cli.Flag{
utils.VersionStateDirFlag,
utils.HashStateDirFlag,
utils.BlockNumber,
},
}
)
func diffDebugState(ctx *cli.Context) error {
if !ctx.IsSet(utils.VersionStateDirFlag.Name) {
return fmt.Errorf("please set `--versionstatedir` flag")
}
if !ctx.IsSet(utils.BlockNumber.Name) {
return fmt.Errorf("please set `--block` flag")
}
if !ctx.IsSet(utils.HashStateDirFlag.Name) {
return fmt.Errorf("please set `--hashstatedir` flag")
}
verDir := ctx.String(utils.VersionStateDirFlag.Name)
hasDir := ctx.String(utils.HashStateDirFlag.Name)
block := ctx.Int64(utils.BlockNumber.Name)
vdb, err := rawdb.Open(rawdb.OpenOptions{
ReadOnly: true,
Type: "pebble",
Directory: verDir,
})
if err != nil {
return err
}
verData, err := vdb.Get(state.DebugVersionStateKey(block))
if err != nil {
return err
}
verDebugState := &state.DebugVersionState{}
err = json.Unmarshal(verData, verDebugState)
if err != nil {
return nil
}
hdb, err := rawdb.Open(rawdb.OpenOptions{
ReadOnly: true,
Type: "pebble",
Directory: hasDir,
})
if err != nil {
return err
}
hashData, err := hdb.Get(state.DebugHashStateKey(block))
if err != nil {
return err
}
hasDebugState := &state.DebugHashState{}
err = json.Unmarshal(hashData, hasDebugState)
if err != nil {
return err
}
res := state.GenerateDebugStateDiff(verDebugState, hasDebugState)
fmt.Println(res)
return nil
}
func getDebugVersionState(ctx *cli.Context) error {
if !ctx.IsSet(utils.VersionStateDirFlag.Name) {
return fmt.Errorf("please set `--versionstatedir` flag")
}
if !ctx.IsSet(utils.BlockNumber.Name) {
return fmt.Errorf("please set `--block` flag")
}
dir := ctx.String(utils.VersionStateDirFlag.Name)
block := ctx.Int64(utils.BlockNumber.Name)
db, err := rawdb.Open(rawdb.OpenOptions{
ReadOnly: true,
Type: "pebble",
Directory: dir,
})
if err != nil {
return err
}
data, err := db.Get(state.DebugVersionStateKey(block))
if err != nil {
return err
}
fmt.Println(string(data))
return nil
}
func getDebugHashState(ctx *cli.Context) error {
if !ctx.IsSet(utils.HashStateDirFlag.Name) {
return fmt.Errorf("please set `--hashstatedir` flag")
}
if !ctx.IsSet(utils.BlockNumber.Name) {
return fmt.Errorf("please set `--block` flag")
}
dir := ctx.String(utils.HashStateDirFlag.Name)
block := ctx.Int64(utils.BlockNumber.Name)
db, err := rawdb.Open(rawdb.OpenOptions{
ReadOnly: true,
Type: "pebble",
Directory: dir,
})
if err != nil {
return err
}
data, err := db.Get(state.DebugHashStateKey(block))
if err != nil {
return err
}
fmt.Println(string(data))
return nil
}
func removeDB(ctx *cli.Context) error {
stack, config := makeConfigNode(ctx)

View File

@@ -72,14 +72,12 @@ var (
utils.USBFlag,
utils.SmartCardDaemonPathFlag,
utils.RialtoHash,
utils.OverridePassedForkTime,
utils.OverrideBohr,
utils.OverrideVerkle,
utils.OverrideFullImmutabilityThreshold,
utils.OverrideMinBlocksForBlobRequests,
utils.OverrideDefaultExtraReserveForBlobRequests,
utils.OverrideBreatheBlockInterval,
utils.OverrideFixedTurnLength,
utils.EnablePersonal,
utils.TxPoolLocalsFlag,
utils.TxPoolNoLocalsFlag,
@@ -232,12 +230,6 @@ var (
utils.MetricsInfluxDBBucketFlag,
utils.MetricsInfluxDBOrganizationFlag,
}
fakeBeaconFlags = []cli.Flag{
utils.FakeBeaconEnabledFlag,
utils.FakeBeaconAddrFlag,
utils.FakeBeaconPortFlag,
}
)
var app = flags.NewApp("the go-ethereum command line interface")
@@ -292,7 +284,6 @@ func init() {
consoleFlags,
debug.Flags,
metricsFlags,
fakeBeaconFlags,
)
flags.AutoEnvVars(app.Flags, "GETH")
@@ -370,6 +361,8 @@ func geth(ctx *cli.Context) error {
defer stack.Close()
startNode(ctx, stack, backend, false)
// TODO:: debug code , will be deleted in the future
debug.StartPProf("127.0.0.1:7060", !ctx.IsSet("metrics.addr"))
stack.Wait()
return nil
}
@@ -378,6 +371,8 @@ 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)
@@ -450,23 +445,22 @@ func startNode(ctx *cli.Context, stack *node.Node, backend ethapi.Backend, isCon
}
// Start auxiliary services if enabled
ethBackend, ok := backend.(*eth.EthAPIBackend)
gasCeil := ethBackend.Miner().GasCeil()
if gasCeil > params.SystemTxsGas {
ethBackend.TxPool().SetMaxGas(gasCeil - params.SystemTxsGas)
}
if ctx.Bool(utils.MiningEnabledFlag.Name) {
// Mining only makes sense if a full Ethereum node is running
if ctx.String(utils.SyncModeFlag.Name) == "light" {
utils.Fatalf("Light clients do not support mining")
}
ethBackend, ok := backend.(*eth.EthAPIBackend)
if !ok {
utils.Fatalf("Ethereum service not running")
}
// Set the gas price to the limits from the CLI and start mining
gasprice := flags.GlobalBig(ctx, utils.MinerGasPriceFlag.Name)
ethBackend.TxPool().SetGasTip(gasprice)
gasCeil := ethBackend.Miner().GasCeil()
if gasCeil > params.SystemTxsGas {
ethBackend.TxPool().SetMaxGas(gasCeil - params.SystemTxsGas)
}
if err := ethBackend.StartMining(); err != nil {
utils.Fatalf("Failed to start mining: %v", err)
}

View File

@@ -33,7 +33,7 @@ node get_perf.js --rpc ${url} --startNum ${start} --endNum ${end}
output as following
```bash
Get the performance between [ 19470 , 19670 )
txCountPerBlock = 3142.81 txCountTotal = 628562 BlockCount = 200 avgBlockTime = 3.005 inturnBlocksRatio = 0.975 justifiedBlocksRatio = 0.98
txCountPerBlock = 3142.81 txCountTotal = 628562 BlockCount = 200 avgBlockTime = 3.005 inturnBlocksRatio = 0.975
txCountPerSecond = 1045.8602329450914 avgGasUsedPerBlock = 250.02062627 avgGasUsedPerSecond = 83.20153952412646
```

View File

@@ -12,9 +12,6 @@ const main = async () => {
let txCountTotal = 0;
let gasUsedTotal = 0;
let inturnBlocks = 0;
let justifiedBlocks = 0;
let turnLength = await provider.send("parlia_getTurnLength", [
ethers.toQuantity(program.startNum)]);
for (let i = program.startNum; i < program.endNum; i++) {
let txCount = await provider.send("eth_getBlockTransactionCountByNumber", [
ethers.toQuantity(i)]);
@@ -29,15 +26,7 @@ const main = async () => {
inturnBlocks += 1
}
let timestamp = eval(eval(header.timestamp).toString(10))
let justifiedNumber = await provider.send("parlia_getJustifiedNumber", [
ethers.toQuantity(i)]);
if (justifiedNumber + 1 == i) {
justifiedBlocks += 1
} else {
console.log("justified unexpected", "BlockNumber =", i,"justifiedNumber",justifiedNumber)
}
console.log("BlockNumber =", i, "mod =", i%turnLength, "miner =", header.miner , "difficulty =", difficulty, "txCount =", ethers.toNumber(txCount), "gasUsed", gasUsed, "timestamp", timestamp)
console.log("BlockNumber =", i, "mod =", i%4, "miner =", header.miner , "difficulty =", difficulty, "txCount =", ethers.toNumber(txCount), "gasUsed", gasUsed, "timestamp", timestamp)
}
let blockCount = program.endNum - program.startNum
@@ -52,14 +41,13 @@ const main = async () => {
let timeCost = endTime - startTime
let avgBlockTime = timeCost/blockCount
let inturnBlocksRatio = inturnBlocks/blockCount
let justifiedBlocksRatio = justifiedBlocks/blockCount
let tps = txCountTotal/timeCost
let M = 1000000
let avgGasUsedPerBlock = gasUsedTotal/blockCount/M
let avgGasUsedPerSecond = gasUsedTotal/timeCost/M
console.log("Get the performance between [", program.startNum, ",", program.endNum, ")");
console.log("txCountPerBlock =", txCountPerBlock, "txCountTotal =", txCountTotal, "BlockCount =", blockCount, "avgBlockTime =", avgBlockTime, "inturnBlocksRatio =", inturnBlocksRatio, "justifiedBlocksRatio =", justifiedBlocksRatio);
console.log("txCountPerBlock =", txCountPerBlock, "txCountTotal =", txCountTotal, "BlockCount =", blockCount, "avgBlockTime =", avgBlockTime, "inturnBlocksRatio =", inturnBlocksRatio);
console.log("txCountPerSecond =", tps, "avgGasUsedPerBlock =", avgGasUsedPerBlock, "avgGasUsedPerSecond =", avgGasUsedPerSecond);
};

View File

@@ -1,164 +0,0 @@
import { ethers } from "ethers";
import program from "commander";
// Global Options:
program.option("--rpc <rpc>", "Rpc");
// GetTxCount Options:
program.option("--startNum <startNum>", "start num")
program.option("--endNum <endNum>", "end num")
program.option("--miner <miner>", "miner", "")
// GetVersion Options:
program.option("--num <Num>", "validator num", 21)
// GetTopAddr Options:
program.option("--topNum <Num>", "top num of address to be displayed", 20)
program.parse(process.argv);
const provider = new ethers.JsonRpcProvider(program.rpc)
function printUsage() {
console.log("Usage:");
console.log(" node getchainstatus.js --help");
console.log(" node getchainstatus.js [subcommand] [options]");
console.log("\nSubcommands:");
console.log(" GetTxCount: find the block with max tx size of a range");
console.log(" GetVersion: dump validators' binary version, based on Header.Extra");
console.log(" GetTopAddr: get hottest $topNum target address within a block range");
console.log("\nOptions:");
console.log(" --rpc specify the url of RPC endpoint");
console.log(" --startNum the start block number, for command GetTxCount");
console.log(" --endNum the end block number, for command GetTxCount");
console.log(" --miner the miner address, for command GetTxCount");
console.log(" --num the number of blocks to be checked, for command GetVersion");
console.log(" --topNum the topNum of blocks to be checked, for command GetVersion");
console.log("\nExample:");
// mainnet https://bsc-mainnet.nodereal.io/v1/454e504917db4f82b756bd0cf6317dce
console.log(" node getchainstatus.js GetTxCount --rpc https://bsc-testnet-dataseed.bnbchain.org --startNum 40000001 --endNum 40000005")
console.log(" node getchainstatus.js GetVersion --rpc https://bsc-testnet-dataseed.bnbchain.org --num 21")
console.log(" node getchainstatus.js GetTopAddr --rpc https://bsc-testnet-dataseed.bnbchain.org --startNum 40000001 --endNum 40000010 --topNum 10")
}
// 1.cmd: "GetTxCount", usage:
// node getchainstatus.js GetTxCount --rpc https://bsc-testnet-dataseed.bnbchain.org \
// --startNum 40000001 --endNum 40000005 \
// --miner(optional): specified: find the max txCounter from the specified validator,
// not specified: find the max txCounter from all validators
async function getTxCount() {
let txCount = 0;
let num = 0;
console.log("Find the max txs count between", program.startNum, "and", program.endNum);
for (let i = program.startNum; i < program.endNum; i++) {
if (program.miner !== "") {
let blockData = await provider.getBlock(Number(i))
if (program.miner !== blockData.miner) {
continue
}
}
let x = await provider.send("eth_getBlockTransactionCountByNumber", [
ethers.toQuantity(i)]);
let a = ethers.toNumber(x)
if (a > txCount) {
num = i;
txCount = a;
}
}
console.log("BlockNum = ", num, "TxCount =", txCount);
}
// 2.cmd: "GetVersion", usage:
// node getchainstatus.js GetVersion \
// --rpc https://bsc-testnet-dataseed.bnbchain.org \
// --num(optional): defualt 21, the number of blocks that will be checked
async function getBinaryVersion() {
const blockNum = await provider.getBlockNumber();
console.log(blockNum);
for (let i = 0; i < program.num; i++) {
let blockData = await provider.getBlock(blockNum - i);
// 1.get Geth client version
let major = ethers.toNumber(ethers.dataSlice(blockData.extraData, 2, 3))
let minor = ethers.toNumber(ethers.dataSlice(blockData.extraData, 3, 4))
let patch = ethers.toNumber(ethers.dataSlice(blockData.extraData, 4, 5))
// 2.get minimum txGasPrice based on the last non-zero-gasprice transaction
let lastGasPrice = 0
for (let txIndex = blockData.transactions.length - 1; txIndex >= 0; txIndex--) {
let txHash = blockData.transactions[txIndex]
let txData = await provider.getTransaction(txHash);
if (txData.gasPrice == 0) {
continue
}
lastGasPrice = txData.gasPrice
break
}
console.log(blockData.miner, "version =", major + "." + minor + "." + patch, " MinGasPrice = " + lastGasPrice)
}
};
// 3.cmd: "GetTopAddr", usage:
// node getchainstatus.js GetTopAddr \
// --rpc https://bsc-testnet-dataseed.bnbchain.org \
// --startNum 40000001 --endNum 40000005 \
// --topNum(optional): the top num of address to be displayed, default 20
function getTopKElements(map, k) {
let entries = Array.from(map.entries());
entries.sort((a, b) => b[1] - a[1]);
return entries.slice(0, k);
}
async function getTopAddr() {
let countMap = new Map();
let totalTxs = 0
console.log("Find the top target address, between", program.startNum, "and", program.endNum);
for (let i = program.startNum; i <= program.endNum; i++) {
let blockData = await provider.getBlock(Number(i), true)
totalTxs += blockData.transactions.length
for (let txIndex = blockData.transactions.length - 1; txIndex >= 0; txIndex--) {
let txData = await blockData.getTransaction(txIndex)
if (txData.to == null) {
console.log("Contract creation,txHash:", txData.hash)
continue
}
let toAddr = txData.to;
if (countMap.has(toAddr)) {
countMap.set(toAddr, countMap.get(toAddr) + 1);
} else {
countMap.set(toAddr, 1);
}
}
console.log("progress:", (program.endNum-i), "blocks left", "totalTxs", totalTxs)
}
let tops = getTopKElements(countMap, program.topNum)
tops.forEach((value, key) => {
// value: [ '0x40661F989826CC641Ce1601526Bb16a4221412c8', 71 ]
console.log(key+":", value[0], " ", value[1], " ", ((value[1]*100)/totalTxs).toFixed(2)+"%");
});
};
const main = async () => {
if (process.argv.length <= 2) {
console.error('invalid process.argv.length', process.argv.length);
printUsage()
return
}
const cmd = process.argv[2]
if (cmd === "--help") {
printUsage()
return
}
if (cmd === "GetTxCount") {
await getTxCount()
} else if (cmd === "GetVersion") {
await getBinaryVersion()
} else if (cmd === "GetTopAddr") {
await getTopAddr()
} else {
console.log("unsupported cmd", cmd);
printUsage()
}
}
main().then(() => process.exit(0))
.catch((error) => {
console.error(error);
process.exit(1);
});

41
cmd/jsutils/gettxcount.js Normal file
View File

@@ -0,0 +1,41 @@
import { ethers } from "ethers";
import program from "commander";
program.option("--rpc <rpc>", "Rpc");
program.option("--startNum <startNum>", "start num")
program.option("--endNum <endNum>", "end num")
// --miner:
// specified: find the max txCounter from the specified validator
// not specified: find the max txCounter from all validators
program.option("--miner <miner>", "miner", "")
program.parse(process.argv);
const provider = new ethers.JsonRpcProvider(program.rpc)
const main = async () => {
let txCount = 0;
let num = 0;
console.log("Find the max txs count between", program.startNum, "and", program.endNum);
for (let i = program.startNum; i < program.endNum; i++) {
if (program.miner !== "") {
let blockData = await provider.getBlock(Number(i))
if (program.miner !== blockData.miner) {
continue
}
}
let x = await provider.send("eth_getBlockTransactionCountByNumber", [
ethers.toQuantity(i)]);
let a = ethers.toNumber(x)
if (a > txCount) {
num = i;
txCount = a;
}
}
console.log("BlockNum = ", num, "TxCount =", txCount);
};
main().then(() => process.exit(0))
.catch((error) => {
console.error(error);
process.exit(1);
});

View File

@@ -0,0 +1,38 @@
import { ethers } from "ethers";
import program from "commander";
program.option("--Rpc <Rpc>", "Rpc");
program.option("--Num <Num>", "validator num", 21)
program.parse(process.argv);
const provider = new ethers.JsonRpcProvider(program.Rpc);
const main = async () => {
const blockNum = await provider.getBlockNumber();
console.log(blockNum);
for (let i = 0; i < program.Num; i++) {
let blockData = await provider.getBlock(blockNum - i);
// 1.get Geth client version
let major = ethers.toNumber(ethers.dataSlice(blockData.extraData, 2, 3))
let minor = ethers.toNumber(ethers.dataSlice(blockData.extraData, 3, 4))
let patch = ethers.toNumber(ethers.dataSlice(blockData.extraData, 4, 5))
// 2.get minimum txGasPrice based on the last non-zero-gasprice transaction
let lastGasPrice = 0
for (let txIndex = blockData.transactions.length - 1; txIndex >= 0; txIndex--) {
let txHash = blockData.transactions[txIndex]
let txData = await provider.getTransaction(txHash);
if (txData.gasPrice == 0) {
continue
}
lastGasPrice = txData.gasPrice
break
}
console.log(blockData.miner, "version =", major + "." + minor + "." + patch, " MinGasPrice = " + lastGasPrice)
}
};
main().then(() => process.exit(0))
.catch((error) => {
console.error(error);
process.exit(1);
});

View File

@@ -35,11 +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"
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/common/fdlimit"
"github.com/ethereum/go-ethereum/core"
@@ -308,11 +305,6 @@ var (
Usage: "Manually specify the Rialto Genesis Hash, to trigger builtin network logic",
Category: flags.EthCategory,
}
OverridePassedForkTime = &cli.Uint64Flag{
Name: "override.passedforktime",
Usage: "Manually specify the hard fork timestamp except the last one, overriding the bundled setting",
Category: flags.EthCategory,
}
OverrideBohr = &cli.Uint64Flag{
Name: "override.bohr",
Usage: "Manually specify the Bohr fork timestamp, overriding the bundled setting",
@@ -347,12 +339,6 @@ var (
Value: params.BreatheBlockInterval,
Category: flags.EthCategory,
}
OverrideFixedTurnLength = &cli.Uint64Flag{
Name: "override.fixedturnlength",
Usage: "It use fixed or random values for turn length instead of reading from the contract, only for testing purpose",
Value: params.FixedTurnLength,
Category: flags.EthCategory,
}
SyncModeFlag = &flags.TextMarshalerFlag{
Name: "syncmode",
Usage: `Blockchain sync mode ("snap" or "full")`,
@@ -367,7 +353,7 @@ var (
}
StateSchemeFlag = &cli.StringFlag{
Name: "state.scheme",
Usage: "Scheme to use for storing ethereum state ('hash' or 'path')",
Usage: "Scheme to use for storing ethereum state ('hash', 'path', 'version')",
Category: flags.StateCategory,
}
PathDBSyncFlag = &cli.BoolFlag{
@@ -1150,23 +1136,23 @@ Please note that --` + MetricsHTTPFlag.Name + ` must be set to start the server.
Category: flags.MiscCategory,
}
// Fake beacon
FakeBeaconEnabledFlag = &cli.BoolFlag{
Name: "fake-beacon",
Usage: "Enable the HTTP-RPC server of fake-beacon",
Category: flags.APICategory,
BlockNumber = &cli.Int64Flag{
Name: "block",
Value: int64(0),
}
FakeBeaconAddrFlag = &cli.StringFlag{
Name: "fake-beacon.addr",
Usage: "HTTP-RPC server listening addr of fake-beacon",
Value: fakebeacon.DefaultAddr,
Category: flags.APICategory,
VersionStateDirFlag = &flags.DirectoryFlag{
Name: "versionstatedir",
Usage: "Data directory for the version databases and keystore",
Value: flags.DirectoryString(node.DefaultDataDir()),
Category: flags.EthCategory,
}
FakeBeaconPortFlag = &cli.IntFlag{
Name: "fake-beacon.port",
Usage: "HTTP-RPC server listening port of fake-beacon",
Value: fakebeacon.DefaultPort,
Category: flags.APICategory,
HashStateDirFlag = &flags.DirectoryFlag{
Name: "hashstatedir",
Usage: "Data directory for the version databases and keystore",
Value: flags.DirectoryString(node.DefaultDataDir()),
Category: flags.EthCategory,
}
)
@@ -1986,11 +1972,17 @@ func SetEthConfig(ctx *cli.Context, stack *node.Node, cfg *ethconfig.Config) {
if ctx.IsSet(StateHistoryFlag.Name) {
cfg.StateHistory = ctx.Uint64(StateHistoryFlag.Name)
}
if ctx.String(StateSchemeFlag.Name) != rawdb.VersionScheme {
scheme, err := ParseCLIAndConfigStateScheme(ctx.String(StateSchemeFlag.Name), cfg.StateScheme)
if err != nil {
Fatalf("%v", err)
}
cfg.StateScheme = scheme
} else {
// TODO:: compatible with cli line and configuration file, currently only supports cli.
cfg.StateScheme = rawdb.VersionScheme
}
// Parse transaction history flag, if user is still using legacy config
// file with 'TxLookupLimit' configured, copy the value to 'TransactionHistory'.
if cfg.TransactionHistory == ethconfig.Defaults.TransactionHistory && cfg.TxLookupLimit != ethconfig.Defaults.TxLookupLimit {
@@ -2319,67 +2311,6 @@ func EnableNodeInfo(poolConfig *legacypool.Config, nodeInfo *p2p.NodeInfo) Setup
}
}
func EnableNodeTrack(ctx *cli.Context, cfg *ethconfig.Config, stack *node.Node) SetupMetricsOption {
nodeInfo := stack.Server().NodeInfo()
return func() {
// register node info into metrics
metrics.NewRegisteredLabel("node-stats", nil).Mark(map[string]interface{}{
"NodeType": parseNodeType(),
"ENR": nodeInfo.ENR,
"Mining": ctx.Bool(MiningEnabledFlag.Name),
"Etherbase": parseEtherbase(cfg),
"MiningFeatures": parseMiningFeatures(ctx, cfg),
"DBFeatures": parseDBFeatures(cfg, stack),
})
}
}
func parseEtherbase(cfg *ethconfig.Config) string {
if cfg.Miner.Etherbase == (common.Address{}) {
return ""
}
return cfg.Miner.Etherbase.String()
}
func parseNodeType() string {
git, _ := version.VCS()
version := []string{params.VersionWithMeta}
if len(git.Commit) >= 7 {
version = append(version, git.Commit[:7])
}
if git.Date != "" {
version = append(version, git.Date)
}
arch := []string{runtime.GOOS, runtime.GOARCH}
infos := []string{"BSC", strings.Join(version, "-"), strings.Join(arch, "-"), runtime.Version()}
return strings.Join(infos, "/")
}
func parseDBFeatures(cfg *ethconfig.Config, stack *node.Node) string {
var features []string
if cfg.StateScheme == rawdb.PathScheme {
features = append(features, "PBSS")
}
if stack.CheckIfMultiDataBase() {
features = append(features, "MultiDB")
}
return strings.Join(features, "|")
}
func parseMiningFeatures(ctx *cli.Context, cfg *ethconfig.Config) string {
if !ctx.Bool(MiningEnabledFlag.Name) {
return ""
}
var features []string
if cfg.Miner.Mev.Enabled {
features = append(features, "MEV")
}
if cfg.Miner.VoteEnable {
features = append(features, "FFVoting")
}
return strings.Join(features, "|")
}
func SetupMetrics(ctx *cli.Context, options ...SetupMetricsOption) {
if metrics.Enabled {
log.Info("Enabling metrics collection")

View File

@@ -59,9 +59,6 @@ type ChainHeaderReader interface {
// GetHighestVerifiedHeader retrieves the highest header verified.
GetHighestVerifiedHeader() *types.Header
// GetVerifiedBlockByHash retrieves the highest verified block.
GetVerifiedBlockByHash(hash common.Hash) *types.Header
// ChasingHead return the best chain head of peers.
ChasingHead() *types.Header
}

View File

@@ -2306,19 +2306,6 @@ const validatorSetABI = `
],
"stateMutability": "view"
},
{
"inputs": [],
"name": "getTurnLength",
"outputs": [
{
"internalType": "uint256",
"name": "",
"type": "uint256"
}
],
"stateMutability": "view",
"type": "function"
},
{
"type": "function",
"name": "getValidators",

View File

@@ -31,7 +31,13 @@ type API struct {
// GetSnapshot retrieves the state snapshot at a given block.
func (api *API) GetSnapshot(number *rpc.BlockNumber) (*Snapshot, error) {
header := api.getHeader(number)
// Retrieve the requested block number (or current if none requested)
var header *types.Header
if number == nil || *number == rpc.LatestBlockNumber {
header = api.chain.CurrentHeader()
} else {
header = api.chain.GetHeaderByNumber(uint64(number.Int64()))
}
// Ensure we have an actually valid block and return its snapshot
if header == nil {
return nil, errUnknownBlock
@@ -50,7 +56,13 @@ func (api *API) GetSnapshotAtHash(hash common.Hash) (*Snapshot, error) {
// GetValidators retrieves the list of validators at the specified block.
func (api *API) GetValidators(number *rpc.BlockNumber) ([]common.Address, error) {
header := api.getHeader(number)
// Retrieve the requested block number (or current if none requested)
var header *types.Header
if number == nil || *number == rpc.LatestBlockNumber {
header = api.chain.CurrentHeader()
} else {
header = api.chain.GetHeaderByNumber(uint64(number.Int64()))
}
// Ensure we have an actually valid block and return the validators from its snapshot
if header == nil {
return nil, errUnknownBlock
@@ -74,65 +86,3 @@ func (api *API) GetValidatorsAtHash(hash common.Hash) ([]common.Address, error)
}
return snap.validators(), nil
}
func (api *API) GetJustifiedNumber(number *rpc.BlockNumber) (uint64, error) {
header := api.getHeader(number)
// Ensure we have an actually valid block and return the validators from its snapshot
if header == nil {
return 0, errUnknownBlock
}
snap, err := api.parlia.snapshot(api.chain, header.Number.Uint64(), header.Hash(), nil)
if err != nil || snap.Attestation == nil {
return 0, err
}
return snap.Attestation.TargetNumber, nil
}
func (api *API) GetTurnLength(number *rpc.BlockNumber) (uint8, error) {
header := api.getHeader(number)
// Ensure we have an actually valid block and return the validators from its snapshot
if header == nil {
return 0, errUnknownBlock
}
snap, err := api.parlia.snapshot(api.chain, header.Number.Uint64(), header.Hash(), nil)
if err != nil || snap.TurnLength == 0 {
return 0, err
}
return snap.TurnLength, nil
}
func (api *API) GetFinalizedNumber(number *rpc.BlockNumber) (uint64, error) {
header := api.getHeader(number)
// Ensure we have an actually valid block and return the validators from its snapshot
if header == nil {
return 0, errUnknownBlock
}
snap, err := api.parlia.snapshot(api.chain, header.Number.Uint64(), header.Hash(), nil)
if err != nil || snap.Attestation == nil {
return 0, err
}
return snap.Attestation.SourceNumber, nil
}
func (api *API) getHeader(number *rpc.BlockNumber) (header *types.Header) {
currentHeader := api.chain.CurrentHeader()
if number == nil || *number == rpc.LatestBlockNumber {
header = currentHeader // current if none requested
} else if *number == rpc.SafeBlockNumber {
justifiedNumber, _, err := api.parlia.GetJustifiedNumberAndHash(api.chain, []*types.Header{currentHeader})
if err != nil {
return nil
}
header = api.chain.GetHeaderByNumber(justifiedNumber)
} else if *number == rpc.FinalizedBlockNumber {
header = api.parlia.GetFinalizedHeader(api.chain, currentHeader)
} else if *number == rpc.PendingBlockNumber {
return nil // no pending blocks on bsc
} else if *number == rpc.EarliestBlockNumber {
header = api.chain.GetHeaderByNumber(0)
} else {
header = api.chain.GetHeaderByNumber(uint64(number.Int64()))
}
return
}

View File

@@ -1,91 +0,0 @@
package parlia
import (
"context"
"errors"
"math/big"
mrand "math/rand"
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/common/hexutil"
"github.com/ethereum/go-ethereum/common/math"
"github.com/ethereum/go-ethereum/consensus"
"github.com/ethereum/go-ethereum/core/systemcontracts"
"github.com/ethereum/go-ethereum/core/types"
"github.com/ethereum/go-ethereum/internal/ethapi"
"github.com/ethereum/go-ethereum/log"
"github.com/ethereum/go-ethereum/params"
"github.com/ethereum/go-ethereum/rpc"
)
func (p *Parlia) getTurnLength(chain consensus.ChainHeaderReader, header *types.Header) (*uint8, error) {
parent := chain.GetHeaderByHash(header.ParentHash)
if parent == nil {
return nil, errors.New("parent not found")
}
var turnLength uint8
if p.chainConfig.IsBohr(parent.Number, parent.Time) {
turnLengthFromContract, err := p.getTurnLengthFromContract(parent)
if err != nil {
return nil, err
}
if turnLengthFromContract == nil {
return nil, errors.New("unexpected error when getTurnLengthFromContract")
}
turnLength = uint8(turnLengthFromContract.Int64())
} else {
turnLength = defaultTurnLength
}
log.Debug("getTurnLength", "turnLength", turnLength)
return &turnLength, nil
}
func (p *Parlia) getTurnLengthFromContract(header *types.Header) (turnLength *big.Int, err error) {
// mock to get turnLength from the contract
if params.FixedTurnLength >= 1 && params.FixedTurnLength <= 9 {
if params.FixedTurnLength == 2 {
return p.getRandTurnLength(header)
}
return big.NewInt(int64(params.FixedTurnLength)), nil
}
ctx, cancel := context.WithCancel(context.Background())
defer cancel()
method := "getTurnLength"
toAddress := common.HexToAddress(systemcontracts.ValidatorContract)
gas := (hexutil.Uint64)(uint64(math.MaxUint64 / 2))
data, err := p.validatorSetABI.Pack(method)
if err != nil {
log.Error("Unable to pack tx for getTurnLength", "error", err)
return nil, err
}
msgData := (hexutil.Bytes)(data)
blockNr := rpc.BlockNumberOrHashWithHash(header.Hash(), false)
result, err := p.ethAPI.Call(ctx, ethapi.TransactionArgs{
Gas: &gas,
To: &toAddress,
Data: &msgData,
}, &blockNr, nil, nil)
if err != nil {
return nil, err
}
if err := p.validatorSetABI.UnpackIntoInterface(&turnLength, method, result); err != nil {
return nil, err
}
return turnLength, nil
}
// getRandTurnLength returns a random valid value, used to test switching turn length
func (p *Parlia) getRandTurnLength(header *types.Header) (turnLength *big.Int, err error) {
turnLengths := [8]uint8{1, 3, 4, 5, 6, 7, 8, 9}
r := mrand.New(mrand.NewSource(int64(header.Time)))
lengthIndex := int(r.Int31n(int32(len(turnLengths))))
return big.NewInt(int64(turnLengths[lengthIndex])), nil
}

View File

@@ -6,7 +6,6 @@ import (
"encoding/hex"
"errors"
"fmt"
"io"
"math"
"math/big"
"math/rand"
@@ -54,13 +53,11 @@ const (
inMemoryHeaders = 86400 // Number of recent headers to keep in memory for double sign detection,
checkpointInterval = 1024 // Number of blocks after which to save the snapshot to the database
defaultEpochLength = uint64(200) // Default number of blocks of checkpoint to update validatorSet from contract
defaultTurnLength = uint8(1) // Default consecutive number of blocks a validator receives priority for block production
defaultEpochLength = uint64(100) // Default number of blocks of checkpoint to update validatorSet from contract
extraVanity = 32 // Fixed number of extra-data prefix bytes reserved for signer vanity
extraSeal = 65 // Fixed number of extra-data suffix bytes reserved for signer seal
nextForkHashSize = 4 // Fixed number of extra-data suffix bytes reserved for nextForkHash.
turnLengthSize = 1 // Fixed number of extra-data suffix bytes reserved for turnLength
validatorBytesLengthBeforeLuban = common.AddressLength
validatorBytesLength = common.AddressLength + types.BLSPublicKeyLength
@@ -129,10 +126,6 @@ var (
// invalid list of validators (i.e. non divisible by 20 bytes).
errInvalidSpanValidators = errors.New("invalid validator list on sprint end block")
// errInvalidTurnLength is returned if a block contains an
// invalid length of turn (i.e. no data left after parsing validators).
errInvalidTurnLength = errors.New("invalid turnLength")
// errInvalidMixDigest is returned if a block's mix digest is non-zero.
errInvalidMixDigest = errors.New("non-zero mix digest")
@@ -143,10 +136,6 @@ var (
// list of validators different than the one the local node calculated.
errMismatchingEpochValidators = errors.New("mismatching validator list on epoch block")
// errMismatchingEpochTurnLength is returned if a sprint block contains a
// turn length different than the one the local node calculated.
errMismatchingEpochTurnLength = errors.New("mismatching turn length on epoch block")
// errInvalidDifficulty is returned if the difficulty of a block is missing.
errInvalidDifficulty = errors.New("invalid difficulty")
@@ -380,7 +369,6 @@ func (p *Parlia) VerifyHeaders(chain consensus.ChainHeaderReader, headers []*typ
// On luban fork, we introduce vote attestation into the header's extra field, so extra format is different from before.
// Before luban fork: |---Extra Vanity---|---Validators Bytes (or Empty)---|---Extra Seal---|
// After luban fork: |---Extra Vanity---|---Validators Number and Validators Bytes (or Empty)---|---Vote Attestation (or Empty)---|---Extra Seal---|
// After bohr fork: |---Extra Vanity---|---Validators Number and Validators Bytes (or Empty)---|---Turn Length (or Empty)---|---Vote Attestation (or Empty)---|---Extra Seal---|
func getValidatorBytesFromHeader(header *types.Header, chainConfig *params.ChainConfig, parliaConfig *params.ParliaConfig) []byte {
if len(header.Extra) <= extraVanity+extraSeal {
return nil
@@ -397,15 +385,11 @@ func getValidatorBytesFromHeader(header *types.Header, chainConfig *params.Chain
return nil
}
num := int(header.Extra[extraVanity])
start := extraVanity + validatorNumberSize
end := start + num*validatorBytesLength
extraMinLen := end + extraSeal
if chainConfig.IsBohr(header.Number, header.Time) {
extraMinLen += turnLengthSize
}
if num == 0 || len(header.Extra) < extraMinLen {
if num == 0 || len(header.Extra) <= extraVanity+extraSeal+num*validatorBytesLength {
return nil
}
start := extraVanity + validatorNumberSize
end := start + num*validatorBytesLength
return header.Extra[start:end]
}
@@ -424,14 +408,11 @@ func getVoteAttestationFromHeader(header *types.Header, chainConfig *params.Chai
attestationBytes = header.Extra[extraVanity : len(header.Extra)-extraSeal]
} else {
num := int(header.Extra[extraVanity])
start := extraVanity + validatorNumberSize + num*validatorBytesLength
if chainConfig.IsBohr(header.Number, header.Time) {
start += turnLengthSize
}
end := len(header.Extra) - extraSeal
if end <= start {
if len(header.Extra) <= extraVanity+extraSeal+validatorNumberSize+num*validatorBytesLength {
return nil, nil
}
start := extraVanity + validatorNumberSize + num*validatorBytesLength
end := len(header.Extra) - extraSeal
attestationBytes = header.Extra[start:end]
}
@@ -623,11 +604,15 @@ func (p *Parlia) verifyHeader(chain consensus.ChainHeaderReader, header *types.H
return fmt.Errorf("invalid excessBlobGas: have %d, expected nil", header.ExcessBlobGas)
case header.BlobGasUsed != nil:
return fmt.Errorf("invalid blobGasUsed: have %d, expected nil", header.BlobGasUsed)
case header.ParentBeaconRoot != nil:
return fmt.Errorf("invalid parentBeaconRoot, have %#x, expected nil", header.ParentBeaconRoot)
case header.WithdrawalsHash != nil:
return fmt.Errorf("invalid WithdrawalsHash, have %#x, expected nil", header.WithdrawalsHash)
}
} else {
switch {
case header.ParentBeaconRoot != nil:
return fmt.Errorf("invalid parentBeaconRoot, have %#x, expected nil", header.ParentBeaconRoot)
case !header.EmptyWithdrawalsHash():
return errors.New("header has wrong WithdrawalsHash")
}
@@ -636,17 +621,6 @@ func (p *Parlia) verifyHeader(chain consensus.ChainHeaderReader, header *types.H
}
}
bohr := chain.Config().IsBohr(header.Number, header.Time)
if !bohr {
if header.ParentBeaconRoot != nil {
return fmt.Errorf("invalid parentBeaconRoot, have %#x, expected nil", header.ParentBeaconRoot)
}
} else {
if header.ParentBeaconRoot == nil || *header.ParentBeaconRoot != (common.Hash{}) {
return fmt.Errorf("invalid parentBeaconRoot, have %#x, expected zero hash", header.ParentBeaconRoot)
}
}
// All basic checks passed, verify cascading fields
return p.verifyCascadingFields(chain, header, parents)
}
@@ -739,28 +713,13 @@ func (p *Parlia) snapshot(chain consensus.ChainHeaderReader, number uint64, hash
}
}
// If we're at the genesis, snapshot the initial state. Alternatively if we have
// piled up more headers than allowed to be reorged (chain reinit from a freezer),
// consider the checkpoint trusted and snapshot it.
// An offset `p.config.Epoch - 1` can ensure getting the right validators.
if number == 0 || ((number+1)%p.config.Epoch == 0 && (len(headers) > int(params.FullImmutabilityThreshold))) {
var (
checkpoint *types.Header
blockHash common.Hash
)
// If we're at the genesis, snapshot the initial state.
if number == 0 {
checkpoint = chain.GetHeaderByNumber(0)
checkpoint := chain.GetHeaderByNumber(number)
if checkpoint != nil {
blockHash = checkpoint.Hash()
}
} else {
checkpoint = chain.GetHeaderByNumber(number + 1 - p.config.Epoch)
blockHeader := chain.GetHeaderByNumber(number)
if blockHeader != nil {
blockHash = blockHeader.Hash()
}
}
if checkpoint != nil && blockHash != (common.Hash{}) {
// get checkpoint data
hash := checkpoint.Hash()
// get validators from headers
validators, voteAddrs, err := parseValidators(checkpoint, p.chainConfig, p.config)
if err != nil {
@@ -768,27 +727,11 @@ func (p *Parlia) snapshot(chain consensus.ChainHeaderReader, number uint64, hash
}
// new snapshot
snap = newSnapshot(p.config, p.signatures, number, blockHash, validators, voteAddrs, p.ethAPI)
// get turnLength from headers and use that for new turnLength
turnLength, err := parseTurnLength(checkpoint, p.chainConfig, p.config)
if err != nil {
return nil, err
}
if turnLength != nil {
snap.TurnLength = *turnLength
}
// snap.Recents is currently empty, which affects the following:
// a. The function SignRecently - This is acceptable since an empty snap.Recents results in a more lenient check.
// b. The function blockTimeVerifyForRamanujanFork - This is also acceptable as it won't be invoked during `snap.apply`.
// c. This may cause a mismatch in the slash systemtx, but the transaction list is not verified during `snap.apply`.
// snap.Attestation is nil, but Snapshot.updateAttestation will handle it correctly.
snap = newSnapshot(p.config, p.signatures, number, hash, validators, voteAddrs, p.ethAPI)
if err := snap.store(p.db); err != nil {
return nil, err
}
log.Info("Stored checkpoint snapshot to disk", "number", number, "hash", blockHash)
log.Info("Stored checkpoint snapshot to disk", "number", number, "hash", hash)
break
}
}
@@ -945,24 +888,6 @@ func (p *Parlia) prepareValidators(header *types.Header) error {
return nil
}
func (p *Parlia) prepareTurnLength(chain consensus.ChainHeaderReader, header *types.Header) error {
if header.Number.Uint64()%p.config.Epoch != 0 ||
!p.chainConfig.IsBohr(header.Number, header.Time) {
return nil
}
turnLength, err := p.getTurnLength(chain, header)
if err != nil {
return err
}
if turnLength != nil {
header.Extra = append(header.Extra, *turnLength)
}
return nil
}
func (p *Parlia) assembleVoteAttestation(chain consensus.ChainHeaderReader, header *types.Header) error {
if !p.chainConfig.IsLuban(header.Number) || header.Number.Uint64() < 2 {
return nil
@@ -1094,9 +1019,6 @@ func (p *Parlia) Prepare(chain consensus.ChainHeaderReader, header *types.Header
return err
}
if err := p.prepareTurnLength(chain, header); err != nil {
return err
}
// add extra seal space
header.Extra = append(header.Extra, make([]byte, extraSeal)...)
@@ -1147,30 +1069,6 @@ func (p *Parlia) verifyValidators(header *types.Header) error {
return nil
}
func (p *Parlia) verifyTurnLength(chain consensus.ChainHeaderReader, header *types.Header) error {
if header.Number.Uint64()%p.config.Epoch != 0 ||
!p.chainConfig.IsBohr(header.Number, header.Time) {
return nil
}
turnLengthFromHeader, err := parseTurnLength(header, p.chainConfig, p.config)
if err != nil {
return err
}
if turnLengthFromHeader != nil {
turnLength, err := p.getTurnLength(chain, header)
if err != nil {
return err
}
if turnLength != nil && *turnLength == *turnLengthFromHeader {
log.Debug("verifyTurnLength", "turnLength", *turnLength)
return nil
}
}
return errMismatchingEpochTurnLength
}
func (p *Parlia) distributeFinalityReward(chain consensus.ChainHeaderReader, state *state.StateDB, header *types.Header,
cx core.ChainContext, txs *[]*types.Transaction, receipts *[]*types.Receipt, systemTxs *[]*types.Transaction,
usedGas *uint64, mining bool) error {
@@ -1265,10 +1163,6 @@ func (p *Parlia) Finalize(chain consensus.ChainHeaderReader, header *types.Heade
return err
}
if err := p.verifyTurnLength(chain, header); err != nil {
return err
}
cx := chainContext{Chain: chain, parlia: p}
parent := chain.GetHeaderByHash(header.ParentHash)
@@ -1295,7 +1189,7 @@ func (p *Parlia) Finalize(chain consensus.ChainHeaderReader, header *types.Heade
}
}
if header.Difficulty.Cmp(diffInTurn) != 0 {
spoiledVal := snap.inturnValidator()
spoiledVal := snap.supposeValidator()
signedRecently := false
if p.chainConfig.IsPlato(header.Number) {
signedRecently = snap.SignRecently(spoiledVal)
@@ -1386,7 +1280,7 @@ func (p *Parlia) FinalizeAndAssemble(chain consensus.ChainHeaderReader, header *
if err != nil {
return nil, nil, err
}
spoiledVal := snap.inturnValidator()
spoiledVal := snap.supposeValidator()
signedRecently := false
if p.chainConfig.IsPlato(header.Number) {
signedRecently = snap.SignRecently(spoiledVal)
@@ -1468,7 +1362,7 @@ func (p *Parlia) IsActiveValidatorAt(chain consensus.ChainHeaderReader, header *
func (p *Parlia) VerifyVote(chain consensus.ChainHeaderReader, vote *types.VoteEnvelope) error {
targetNumber := vote.Data.TargetNumber
targetHash := vote.Data.TargetHash
header := chain.GetVerifiedBlockByHash(targetHash)
header := chain.GetHeaderByHash(targetHash)
if header == nil {
log.Warn("BlockHeader at current voteBlockNumber is nil", "targetNumber", targetNumber, "targetHash", targetHash)
return errors.New("BlockHeader at current voteBlockNumber is nil")
@@ -1539,13 +1433,10 @@ func (p *Parlia) Delay(chain consensus.ChainReader, header *types.Header, leftOv
delay = delay - *leftOver
}
// The blocking time should be no more than half of period when snap.TurnLength == 1
timeForMining := time.Duration(p.config.Period) * time.Second / 2
if !snap.lastBlockInOneTurn(header.Number.Uint64()) {
timeForMining = time.Duration(p.config.Period) * time.Second * 2 / 3
}
if delay > timeForMining {
delay = timeForMining
// The blocking time should be no more than half of period
half := time.Duration(p.config.Period) * time.Second / 2
if delay > half {
delay = half
}
return &delay
}
@@ -1703,35 +1594,11 @@ func CalcDifficulty(snap *Snapshot, signer common.Address) *big.Int {
return new(big.Int).Set(diffNoTurn)
}
func encodeSigHeaderWithoutVoteAttestation(w io.Writer, header *types.Header, chainId *big.Int) {
err := rlp.Encode(w, []interface{}{
chainId,
header.ParentHash,
header.UncleHash,
header.Coinbase,
header.Root,
header.TxHash,
header.ReceiptHash,
header.Bloom,
header.Difficulty,
header.Number,
header.GasLimit,
header.GasUsed,
header.Time,
header.Extra[:extraVanity], // this will panic if extra is too short, should check before calling encodeSigHeaderWithoutVoteAttestation
header.MixDigest,
header.Nonce,
})
if err != nil {
panic("can't encode: " + err.Error())
}
}
// SealHash returns the hash of a block without vote attestation prior to it being sealed.
// So it's not the real hash of a block, just used as unique id to distinguish task
func (p *Parlia) SealHash(header *types.Header) (hash common.Hash) {
hasher := sha3.NewLegacyKeccak256()
encodeSigHeaderWithoutVoteAttestation(hasher, header, p.chainConfig.ChainID)
types.EncodeSigHeaderWithoutVoteAttestation(hasher, header, p.chainConfig.ChainID)
hasher.Sum(hash[:0])
return hash
}
@@ -2037,40 +1904,42 @@ func (p *Parlia) GetFinalizedHeader(chain consensus.ChainHeaderReader, header *t
// =========================== utility function ==========================
func (p *Parlia) backOffTime(snap *Snapshot, header *types.Header, val common.Address) uint64 {
if snap.inturn(val) {
log.Debug("backOffTime", "blockNumber", header.Number, "in turn validator", val)
return 0
} else {
delay := initialBackOffTime
validators := snap.validators()
if p.chainConfig.IsPlanck(header.Number) {
counts := snap.countRecents()
for addr, seenTimes := range counts {
log.Debug("backOffTime", "blockNumber", header.Number, "validator", addr, "seenTimes", seenTimes)
// reverse the key/value of snap.Recents to get recentsMap
recentsMap := make(map[common.Address]uint64, len(snap.Recents))
bound := uint64(0)
if n, limit := header.Number.Uint64(), uint64(len(validators)/2+1); n > limit {
bound = n - limit
}
for seen, recent := range snap.Recents {
if seen <= bound {
continue
}
recentsMap[recent] = seen
}
// The backOffTime does not matter when a validator has signed recently.
if snap.signRecentlyByCounts(val, counts) {
if _, ok := recentsMap[val]; ok {
return 0
}
inTurnAddr := snap.inturnValidator()
if snap.signRecentlyByCounts(inTurnAddr, counts) {
inTurnAddr := validators[(snap.Number+1)%uint64(len(validators))]
if _, ok := recentsMap[inTurnAddr]; ok {
log.Debug("in turn validator has recently signed, skip initialBackOffTime",
"inTurnAddr", inTurnAddr)
delay = 0
}
// Exclude the recently signed validators and the in turn validator
// Exclude the recently signed validators
temp := make([]common.Address, 0, len(validators))
for _, addr := range validators {
if snap.signRecentlyByCounts(addr, counts) {
if _, ok := recentsMap[addr]; ok {
continue
}
if p.chainConfig.IsBohr(header.Number, header.Time) {
if addr == inTurnAddr {
continue
}
}
temp = append(temp, addr)
}
validators = temp
@@ -2088,11 +1957,7 @@ func (p *Parlia) backOffTime(snap *Snapshot, header *types.Header, val common.Ad
return 0
}
randSeed := snap.Number
if p.chainConfig.IsBohr(header.Number, header.Time) {
randSeed = header.Number.Uint64() / uint64(snap.TurnLength)
}
s := rand.NewSource(int64(randSeed))
s := rand.NewSource(int64(snap.Number))
r := rand.New(s)
n := len(validators)
backOffSteps := make([]uint64, 0, n)

View File

@@ -22,44 +22,22 @@ func TestImpactOfValidatorOutOfService(t *testing.T) {
testCases := []struct {
totalValidators int
downValidators int
turnLength int
}{
{3, 1, 1},
{5, 2, 1},
{10, 1, 2},
{10, 4, 2},
{21, 1, 3},
{21, 3, 3},
{21, 5, 4},
{21, 10, 5},
{3, 1},
{5, 2},
{10, 1},
{10, 4},
{21, 1},
{21, 3},
{21, 5},
{21, 10},
}
for _, tc := range testCases {
simulateValidatorOutOfService(tc.totalValidators, tc.downValidators, tc.turnLength)
simulateValidatorOutOfService(tc.totalValidators, tc.downValidators)
}
}
// refer Snapshot.SignRecently
func signRecently(idx int, recents map[uint64]int, turnLength int) bool {
recentSignTimes := 0
for _, signIdx := range recents {
if signIdx == idx {
recentSignTimes += 1
}
}
return recentSignTimes >= turnLength
}
// refer Snapshot.minerHistoryCheckLen
func minerHistoryCheckLen(totalValidators int, turnLength int) uint64 {
return uint64(totalValidators/2+1)*uint64(turnLength) - 1
}
// refer Snapshot.inturnValidator
func inturnValidator(totalValidators int, turnLength int, height int) int {
return height / turnLength % totalValidators
}
func simulateValidatorOutOfService(totalValidators int, downValidators int, turnLength int) {
func simulateValidatorOutOfService(totalValidators int, downValidators int) {
downBlocks := 10000
recoverBlocks := 10000
recents := make(map[uint64]int)
@@ -77,7 +55,12 @@ func simulateValidatorOutOfService(totalValidators int, downValidators int, turn
delete(validators, down[i])
}
isRecentSign := func(idx int) bool {
return signRecently(idx, recents, turnLength)
for _, signIdx := range recents {
if signIdx == idx {
return true
}
}
return false
}
isInService := func(idx int) bool {
return validators[idx]
@@ -85,10 +68,10 @@ func simulateValidatorOutOfService(totalValidators int, downValidators int, turn
downDelay := uint64(0)
for h := 1; h <= downBlocks; h++ {
if limit := minerHistoryCheckLen(totalValidators, turnLength) + 1; uint64(h) >= limit {
if limit := uint64(totalValidators/2 + 1); uint64(h) >= limit {
delete(recents, uint64(h)-limit)
}
proposer := inturnValidator(totalValidators, turnLength, h)
proposer := h % totalValidators
if !isInService(proposer) || isRecentSign(proposer) {
candidates := make(map[int]bool, totalValidators/2)
for v := range validators {
@@ -116,10 +99,10 @@ func simulateValidatorOutOfService(totalValidators int, downValidators int, turn
recoverDelay := uint64(0)
lastseen := downBlocks
for h := downBlocks + 1; h <= downBlocks+recoverBlocks; h++ {
if limit := minerHistoryCheckLen(totalValidators, turnLength) + 1; uint64(h) >= limit {
if limit := uint64(totalValidators/2 + 1); uint64(h) >= limit {
delete(recents, uint64(h)-limit)
}
proposer := inturnValidator(totalValidators, turnLength, h)
proposer := h % totalValidators
if !isInService(proposer) || isRecentSign(proposer) {
lastseen = h
candidates := make(map[int]bool, totalValidators/2)

View File

@@ -22,7 +22,6 @@ import (
"encoding/json"
"errors"
"fmt"
"math"
"sort"
lru "github.com/hashicorp/golang-lru"
@@ -44,7 +43,6 @@ type Snapshot struct {
Number uint64 `json:"number"` // Block number where the snapshot was created
Hash common.Hash `json:"hash"` // Block hash where the snapshot was created
TurnLength uint8 `json:"turn_length"` // Length of `turn`, meaning the consecutive number of blocks a validator receives priority for block production
Validators map[common.Address]*ValidatorInfo `json:"validators"` // Set of authorized validators at this moment
Recents map[uint64]common.Address `json:"recents"` // Set of recent validators for spam protections
RecentForkHashes map[uint64]string `json:"recent_fork_hashes"` // Set of recent forkHash
@@ -74,7 +72,6 @@ func newSnapshot(
sigCache: sigCache,
Number: number,
Hash: hash,
TurnLength: defaultTurnLength,
Recents: make(map[uint64]common.Address),
RecentForkHashes: make(map[uint64]string),
Validators: make(map[common.Address]*ValidatorInfo),
@@ -117,10 +114,6 @@ func loadSnapshot(config *params.ParliaConfig, sigCache *lru.ARCCache, db ethdb.
if err := json.Unmarshal(blob, snap); err != nil {
return nil, err
}
if snap.TurnLength == 0 { // no TurnLength field in old snapshots
snap.TurnLength = defaultTurnLength
}
snap.config = config
snap.sigCache = sigCache
snap.ethAPI = ethAPI
@@ -145,7 +138,6 @@ func (s *Snapshot) copy() *Snapshot {
sigCache: s.sigCache,
Number: s.Number,
Hash: s.Hash,
TurnLength: s.TurnLength,
Validators: make(map[common.Address]*ValidatorInfo),
Recents: make(map[uint64]common.Address),
RecentForkHashes: make(map[uint64]string),
@@ -218,45 +210,17 @@ func (s *Snapshot) updateAttestation(header *types.Header, chainConfig *params.C
}
}
func (s *Snapshot) versionHistoryCheckLen() uint64 {
return uint64(len(s.Validators)) * uint64(s.TurnLength)
}
func (s *Snapshot) minerHistoryCheckLen() uint64 {
return (uint64(len(s.Validators))/2+1)*uint64(s.TurnLength) - 1
}
func (s *Snapshot) countRecents() map[common.Address]uint8 {
leftHistoryBound := uint64(0) // the bound is excluded
checkHistoryLength := s.minerHistoryCheckLen()
if s.Number > checkHistoryLength {
leftHistoryBound = s.Number - checkHistoryLength
}
counts := make(map[common.Address]uint8, len(s.Validators))
func (s *Snapshot) SignRecently(validator common.Address) bool {
for seen, recent := range s.Recents {
if seen <= leftHistoryBound || recent == (common.Address{}) /*when seen == `epochKey`*/ {
continue
}
counts[recent] += 1
}
return counts
}
func (s *Snapshot) signRecentlyByCounts(validator common.Address, counts map[common.Address]uint8) bool {
if seenTimes, ok := counts[validator]; ok && seenTimes >= s.TurnLength {
if seenTimes > s.TurnLength {
log.Warn("produce more blocks than expected!", "validator", validator, "seenTimes", seenTimes)
}
if recent == validator {
if limit := uint64(len(s.Validators)/2 + 1); s.Number+1 < limit || seen > s.Number+1-limit {
return true
}
}
}
return false
}
func (s *Snapshot) SignRecently(validator common.Address) bool {
return s.signRecentlyByCounts(validator, s.countRecents())
}
func (s *Snapshot) apply(headers []*types.Header, chain consensus.ChainHeaderReader, parents []*types.Header, chainConfig *params.ChainConfig) (*Snapshot, error) {
// Allow passing in no headers for cleaner code
if len(headers) == 0 {
@@ -283,10 +247,10 @@ func (s *Snapshot) apply(headers []*types.Header, chain consensus.ChainHeaderRea
for _, header := range headers {
number := header.Number.Uint64()
// Delete the oldest validator from the recent list to allow it signing again
if limit := snap.minerHistoryCheckLen() + 1; number >= limit {
if limit := uint64(len(snap.Validators)/2 + 1); number >= limit {
delete(snap.Recents, number-limit)
}
if limit := snap.versionHistoryCheckLen(); number >= limit {
if limit := uint64(len(snap.Validators)); number >= limit {
delete(snap.RecentForkHashes, number-limit)
}
// Resolve the authorization key and check against signers
@@ -297,47 +261,19 @@ func (s *Snapshot) apply(headers []*types.Header, chain consensus.ChainHeaderRea
if _, ok := snap.Validators[validator]; !ok {
return nil, errUnauthorizedValidator(validator.String())
}
if chainConfig.IsBohr(header.Number, header.Time) {
if snap.SignRecently(validator) {
return nil, errRecentlySigned
}
} else {
for _, recent := range snap.Recents {
if recent == validator {
return nil, errRecentlySigned
}
}
}
snap.Recents[number] = validator
snap.RecentForkHashes[number] = hex.EncodeToString(header.Extra[extraVanity-nextForkHashSize : extraVanity])
snap.updateAttestation(header, chainConfig, s.config)
// change validator set
if number > 0 && number%s.config.Epoch == snap.minerHistoryCheckLen() {
epochKey := math.MaxUint64 - header.Number.Uint64()/s.config.Epoch // impossible used as a block number
if chainConfig.IsBohr(header.Number, header.Time) {
// after switching the validator set, snap.Validators may become larger,
// then the unexpected second switch will happen, just skip it.
if _, ok := snap.Recents[epochKey]; ok {
continue
}
}
checkpointHeader := FindAncientHeader(header, snap.minerHistoryCheckLen(), chain, parents)
if number > 0 && number%s.config.Epoch == uint64(len(snap.Validators)/2) {
checkpointHeader := FindAncientHeader(header, uint64(len(snap.Validators)/2), chain, parents)
if checkpointHeader == nil {
return nil, consensus.ErrUnknownAncestor
}
oldVersionsLen := snap.versionHistoryCheckLen()
// get turnLength from headers and use that for new turnLength
turnLength, err := parseTurnLength(checkpointHeader, chainConfig, s.config)
if err != nil {
return nil, err
}
if turnLength != nil {
snap.TurnLength = *turnLength
log.Debug("validator set switch", "turnLength", *turnLength)
}
// get validators from headers and use that for new validator set
newValArr, voteAddrs, err := parseValidators(checkpointHeader, chainConfig, s.config)
if err != nil {
@@ -353,12 +289,6 @@ func (s *Snapshot) apply(headers []*types.Header, chain consensus.ChainHeaderRea
}
}
}
if chainConfig.IsBohr(header.Number, header.Time) {
// BEP-404: Clear Miner History when Switching Validators Set
snap.Recents = make(map[uint64]common.Address)
snap.Recents[epochKey] = common.Address{}
log.Debug("Recents are cleared up", "blockNumber", number)
} else {
oldLimit := len(snap.Validators)/2 + 1
newLimit := len(newVals)/2 + 1
if newLimit < oldLimit {
@@ -366,6 +296,12 @@ func (s *Snapshot) apply(headers []*types.Header, chain consensus.ChainHeaderRea
delete(snap.Recents, number-uint64(newLimit)-uint64(i))
}
}
oldLimit = len(snap.Validators)
newLimit = len(newVals)
if newLimit < oldLimit {
for i := 0; i < oldLimit-newLimit; i++ {
delete(snap.RecentForkHashes, number-uint64(newLimit)-uint64(i))
}
}
snap.Validators = newVals
if chainConfig.IsLuban(header.Number) {
@@ -374,10 +310,11 @@ func (s *Snapshot) apply(headers []*types.Header, chain consensus.ChainHeaderRea
snap.Validators[val].Index = idx + 1 // offset by 1
}
}
for i := snap.versionHistoryCheckLen(); i < oldVersionsLen; i++ {
delete(snap.RecentForkHashes, number-i)
}
}
snap.updateAttestation(header, chainConfig, s.config)
snap.RecentForkHashes[number] = hex.EncodeToString(header.Extra[extraVanity-nextForkHashSize : extraVanity])
}
snap.Number += uint64(len(headers))
snap.Hash = headers[len(headers)-1].Hash()
@@ -394,20 +331,17 @@ func (s *Snapshot) validators() []common.Address {
return validators
}
// lastBlockInOneTurn returns if the block at height `blockNumber` is the last block in current turn.
func (s *Snapshot) lastBlockInOneTurn(blockNumber uint64) bool {
return (blockNumber+1)%uint64(s.TurnLength) == 0
}
// inturn returns if a validator at a given block height is in-turn or not.
func (s *Snapshot) inturn(validator common.Address) bool {
return s.inturnValidator() == validator
validators := s.validators()
offset := (s.Number + 1) % uint64(len(validators))
return validators[offset] == validator
}
// inturnValidator returns the validator for the following block height.
// inturnValidator returns the validator at a given block height.
func (s *Snapshot) inturnValidator() common.Address {
validators := s.validators()
offset := (s.Number + 1) / uint64(s.TurnLength) % uint64(len(validators))
offset := (s.Number + 1) % uint64(len(validators))
return validators[offset]
}
@@ -445,6 +379,12 @@ func (s *Snapshot) indexOfVal(validator common.Address) int {
return -1
}
func (s *Snapshot) supposeValidator() common.Address {
validators := s.validators()
index := (s.Number + 1) % uint64(len(validators))
return validators[index]
}
func parseValidators(header *types.Header, chainConfig *params.ChainConfig, parliaConfig *params.ParliaConfig) ([]common.Address, []types.BLSPublicKey, error) {
validatorsBytes := getValidatorBytesFromHeader(header, chainConfig, parliaConfig)
if len(validatorsBytes) == 0 {
@@ -470,24 +410,6 @@ func parseValidators(header *types.Header, chainConfig *params.ChainConfig, parl
return cnsAddrs, voteAddrs, nil
}
func parseTurnLength(header *types.Header, chainConfig *params.ChainConfig, parliaConfig *params.ParliaConfig) (*uint8, error) {
if header.Number.Uint64()%parliaConfig.Epoch != 0 ||
!chainConfig.IsBohr(header.Number, header.Time) {
return nil, nil
}
if len(header.Extra) <= extraVanity+extraSeal {
return nil, errInvalidSpanValidators
}
num := int(header.Extra[extraVanity])
pos := extraVanity + validatorNumberSize + num*validatorBytesLength
if len(header.Extra) <= pos {
return nil, errInvalidTurnLength
}
turnLength := header.Extra[pos]
return &turnLength, nil
}
func FindAncientHeader(header *types.Header, ite uint64, chain consensus.ChainHeaderReader, candidateParents []*types.Header) *types.Header {
ancient := header
for i := uint64(1); i <= ite; i++ {

View File

@@ -74,6 +74,7 @@ var (
blockInsertMgaspsGauge = metrics.NewRegisteredGauge("chain/insert/mgasps", nil)
chainInfoGauge = metrics.NewRegisteredGaugeInfo("chain/info", nil)
mGasPsGauge = metrics.NewRegisteredGauge("chain/process/gas", nil)
accountReadTimer = metrics.NewRegisteredTimer("chain/account/reads", nil)
accountHashTimer = metrics.NewRegisteredTimer("chain/account/hashes", nil)
@@ -100,8 +101,6 @@ 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")
@@ -198,6 +197,10 @@ func (c *CacheConfig) triedbConfig() *triedb.Config {
JournalFile: c.JournalFile,
}
}
// TODO:: support other versa db config items, currently use the default config
if c.StateScheme == rawdb.VersionScheme {
config.IsVersion = true
}
return config
}
@@ -270,7 +273,6 @@ type BlockChain struct {
logsFeed event.Feed
blockProcFeed event.Feed
finalizedHeaderFeed event.Feed
highestVerifiedBlockFeed event.Feed
scope event.SubscriptionScope
genesisBlock *types.Block
@@ -279,7 +281,6 @@ type BlockChain struct {
chainmu *syncx.ClosableMutex
highestVerifiedHeader atomic.Pointer[types.Header]
highestVerifiedBlock atomic.Pointer[types.Header]
currentBlock atomic.Pointer[types.Header] // Current head of the chain
currentSnapBlock atomic.Pointer[types.Header] // Current head of snap-sync
currentFinalBlock atomic.Pointer[types.Header] // Latest (consensus) finalized block
@@ -388,7 +389,7 @@ func NewBlockChain(db ethdb.Database, cacheConfig *CacheConfig, genesis *Genesis
}
bc.flushInterval.Store(int64(cacheConfig.TrieTimeLimit))
bc.forker = NewForkChoice(bc, shouldPreserve)
bc.stateCache = state.NewDatabaseWithNodeDB(bc.db, bc.triedb)
bc.stateCache = state.NewDatabaseWithNodeDB(bc.db, bc.triedb, true)
bc.validator = NewBlockValidator(chainConfig, bc, engine)
bc.prefetcher = NewStatePrefetcher(chainConfig, bc, engine)
bc.processor = NewStateProcessor(chainConfig, bc, engine)
@@ -404,7 +405,6 @@ func NewBlockChain(db ethdb.Database, cacheConfig *CacheConfig, genesis *Genesis
}
bc.highestVerifiedHeader.Store(nil)
bc.highestVerifiedBlock.Store(nil)
bc.currentBlock.Store(nil)
bc.currentSnapBlock.Store(nil)
bc.chasingHead.Store(nil)
@@ -1170,6 +1170,10 @@ func (bc *BlockChain) setHeadBeyondRoot(head uint64, time uint64, root common.Ha
// SnapSyncCommitHead sets the current head block to the one defined by the hash
// irrelevant what the chain contents were prior.
func (bc *BlockChain) SnapSyncCommitHead(hash common.Hash) error {
// TODO:: temporarily not support for snapsync
if bc.triedb.Scheme() == rawdb.VersionScheme {
panic("version db not support snap sync")
}
// Make sure that both the block as well at its state trie exists
block := bc.GetBlockByHash(hash)
if block == nil {
@@ -1381,6 +1385,7 @@ func (bc *BlockChain) Stop() {
}
bc.snaps.Release()
}
if bc.triedb.Scheme() != rawdb.VersionScheme {
if bc.triedb.Scheme() == rawdb.PathScheme {
// Ensure that the in-memory trie nodes are journaled to disk properly.
if err := bc.triedb.Journal(bc.CurrentBlock().Root); err != nil {
@@ -1395,7 +1400,7 @@ func (bc *BlockChain) Stop() {
if !bc.cacheConfig.TrieDirtyDisabled {
triedb := bc.triedb
var once sync.Once
for _, offset := range []uint64{0, 1, bc.TriesInMemory() - 1} {
for _, offset := range []uint64{0, 1, TriesInMemory - 1} {
if number := bc.CurrentBlock().Number.Uint64(); number > offset {
recent := bc.GetBlockByNumber(number - offset)
log.Info("Writing cached state to disk", "block", recent.Number(), "hash", recent.Hash(), "root", recent.Root())
@@ -1426,6 +1431,7 @@ func (bc *BlockChain) Stop() {
}
}
}
}
// Close the trie database, release all the held resources as the last step.
if err := bc.triedb.Close(); err != nil {
log.Error("Failed to close trie database", "err", err)
@@ -1805,7 +1811,7 @@ func (bc *BlockChain) writeBlockWithState(block *types.Block, receipts []*types.
}
bc.hc.tdCache.Add(block.Hash(), externTd)
bc.blockCache.Add(block.Hash(), block)
bc.cacheReceipts(block.Hash(), receipts, block)
bc.receiptsCache.Add(block.Hash(), receipts)
if bc.chainConfig.IsCancun(block.Number(), block.Time()) {
bc.sidecarsCache.Add(block.Hash(), block.Sidecars())
}
@@ -1818,7 +1824,7 @@ func (bc *BlockChain) writeBlockWithState(block *types.Block, receipts []*types.
// If node is running in path mode, skip explicit gc operation
// which is unnecessary in this mode.
if bc.triedb.Scheme() == rawdb.PathScheme {
if bc.triedb.Scheme() != rawdb.HashScheme {
return nil
}
@@ -1833,7 +1839,7 @@ func (bc *BlockChain) writeBlockWithState(block *types.Block, receipts []*types.
// Flush limits are not considered for the first TriesInMemory blocks.
current := block.NumberU64()
if current <= bc.TriesInMemory() {
if current <= TriesInMemory {
return nil
}
// If we exceeded our memory allowance, flush matured singleton nodes to disk
@@ -1931,19 +1937,14 @@ func (bc *BlockChain) WriteBlockAndSetHead(block *types.Block, receipts []*types
// writeBlockAndSetHead is the internal implementation of WriteBlockAndSetHead.
// This function expects the chain mutex to be held.
func (bc *BlockChain) writeBlockAndSetHead(block *types.Block, receipts []*types.Receipt, logs []*types.Log, state *state.StateDB, emitHeadEvent bool) (status WriteStatus, err error) {
if err := bc.writeBlockWithState(block, receipts, state); err != nil {
return NonStatTy, err
}
currentBlock := bc.CurrentBlock()
reorg, err := bc.forker.ReorgNeededWithFastFinality(currentBlock, block.Header())
if err != nil {
return NonStatTy, err
}
if reorg {
bc.highestVerifiedBlock.Store(types.CopyHeader(block.Header()))
bc.highestVerifiedBlockFeed.Send(HighestVerifiedBlockEvent{Header: block.Header()})
}
if err := bc.writeBlockWithState(block, receipts, state); err != nil {
return NonStatTy, err
}
if reorg {
// Reorganise the chain if the parent is not the head block
if block.ParentHash() != currentBlock.Hash() {
@@ -2057,9 +2058,6 @@ 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)
@@ -2245,28 +2243,36 @@ func (bc *BlockChain) insertChain(chain types.Blocks, setHead bool) (int, error)
parent = bc.GetHeader(block.ParentHash(), block.NumberU64()-1)
}
if bc.stateCache.Scheme() != rawdb.VersionScheme {
if block.NumberU64() == 2000001 {
log.Crit("exit.... path mode, 200w blocks")
}
}
bc.stateCache.SetVersion(int64(block.NumberU64()))
statedb, err := state.NewWithSharedPool(parent.Root, bc.stateCache, bc.snaps)
if err != nil {
bc.stateCache.Release()
return it.index, err
}
bc.updateHighestVerifiedHeader(block.Header())
// Enable prefetching to pull in trie node paths while processing transactions
statedb.StartPrefetcher("chain")
//statedb.StartPrefetcher("chain")
interruptCh := make(chan struct{})
// For diff sync, it may fallback to full sync, so we still do prefetch
if len(block.Transactions()) >= prefetchTxNumber {
// do Prefetch in a separate goroutine to avoid blocking the critical path
// 1.do state prefetch for snapshot cache
throwaway := statedb.CopyDoPrefetch()
go bc.prefetcher.Prefetch(block, throwaway, &bc.vmConfig, interruptCh)
// 2.do trie prefetch for MPT trie node cache
// it is for the big state trie tree, prefetch based on transaction's From/To address.
// trie prefetcher is thread safe now, ok to prefetch in a separate routine
go throwaway.TriePrefetchInAdvance(block, signer)
}
//if len(block.Transactions()) >= prefetchTxNumber {
// // do Prefetch in a separate goroutine to avoid blocking the critical path
//
// // 1.do state prefetch for snapshot cache
// throwaway := statedb.CopyDoPrefetch()
// go bc.prefetcher.Prefetch(block, throwaway, &bc.vmConfig, interruptCh)
//
// // 2.do trie prefetch for MPT trie node cache
// // it is for the big state trie tree, prefetch based on transaction's From/To address.
// // trie prefetcher is thread safe now, ok to prefetch in a separate routine
// go throwaway.TriePrefetchInAdvance(block, signer)
//}
// Process block using the parent state as reference point
if bc.pipeCommit {
@@ -2277,6 +2283,7 @@ func (bc *BlockChain) insertChain(chain types.Blocks, setHead bool) (int, error)
statedb, receipts, logs, usedGas, err := bc.processor.Process(block, statedb, bc.vmConfig)
close(interruptCh) // state prefetch can be stopped
if err != nil {
bc.stateCache.Release()
bc.reportBlock(block, receipts, err)
statedb.StopPrefetcher()
return it.index, err
@@ -2286,7 +2293,7 @@ func (bc *BlockChain) insertChain(chain types.Blocks, setHead bool) (int, error)
// Validate the state using the default validator
vstart := time.Now()
if err := bc.validator.ValidateState(block, statedb, receipts, usedGas); err != nil {
log.Error("validate state failed", "error", err)
bc.stateCache.Release()
bc.reportBlock(block, receipts, err)
statedb.StopPrefetcher()
return it.index, err
@@ -2322,8 +2329,12 @@ func (bc *BlockChain) insertChain(chain types.Blocks, setHead bool) (int, error)
status, err = bc.writeBlockAndSetHead(block, receipts, logs, statedb, false)
}
if err != nil {
bc.stateCache.Release()
return it.index, err
}
bc.stateCache.Release()
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

View File

@@ -64,6 +64,7 @@ func (st *insertStats) report(chain []*types.Block, index int, snapDiffItems, sn
"blocks", st.processed, "txs", txs, "blobs", blobs, "mgas", float64(st.usedGas) / 1000000,
"elapsed", common.PrettyDuration(elapsed), "mgasps", mgasps,
}
mGasPsGauge.Update(int64(mgasps))
blockInsertMgaspsGauge.Update(int64(mgasps))
if timestamp := time.Unix(int64(end.Time()), 0); time.Since(timestamp) > time.Minute {
context = append(context, []interface{}{"age", common.PrettyAge(timestamp)}...)

View File

@@ -98,15 +98,6 @@ func (bc *BlockChain) GetHeaderByHash(hash common.Hash) *types.Header {
return bc.hc.GetHeaderByHash(hash)
}
// GetVerifiedBlockByHash retrieves the header of a verified block, it may be only in memory.
func (bc *BlockChain) GetVerifiedBlockByHash(hash common.Hash) *types.Header {
highestVerifiedBlock := bc.highestVerifiedBlock.Load()
if highestVerifiedBlock != nil && highestVerifiedBlock.Hash() == hash {
return highestVerifiedBlock
}
return bc.hc.GetHeaderByHash(hash)
}
// GetHeaderByNumber retrieves a block header from the database by number,
// caching it (associated with its hash) if found.
func (bc *BlockChain) GetHeaderByNumber(number uint64) *types.Header {
@@ -357,8 +348,7 @@ func (bc *BlockChain) HasState(hash common.Hash) bool {
return true
}
}
_, err := bc.stateCache.OpenTrie(hash)
return err == nil
return bc.stateCache.HasState(hash)
}
// HasBlockAndState checks if a block and associated state trie is fully present
@@ -405,7 +395,8 @@ func (bc *BlockChain) State() (*state.StateDB, error) {
// StateAt returns a new mutable state based on a particular point in time.
func (bc *BlockChain) StateAt(root common.Hash) (*state.StateDB, error) {
stateDb, err := state.New(root, bc.stateCache, bc.snaps)
// new state db with no need commit mode
stateDb, err := state.New(root, state.NewDatabaseWithNodeDB(bc.db, bc.triedb, false), bc.snaps)
if err != nil {
return nil, err
}
@@ -495,11 +486,6 @@ func (bc *BlockChain) SubscribeChainHeadEvent(ch chan<- ChainHeadEvent) event.Su
return bc.scope.Track(bc.chainHeadFeed.Subscribe(ch))
}
// SubscribeHighestVerifiedBlockEvent registers a subscription of HighestVerifiedBlockEvent.
func (bc *BlockChain) SubscribeHighestVerifiedHeaderEvent(ch chan<- HighestVerifiedBlockEvent) event.Subscription {
return bc.scope.Track(bc.highestVerifiedBlockFeed.Subscribe(ch))
}
// SubscribeChainBlockEvent registers a subscription of ChainBlockEvent.
func (bc *BlockChain) SubscribeChainBlockEvent(ch chan<- ChainHeadEvent) event.Subscription {
return bc.scope.Track(bc.chainBlockFeed.Subscribe(ch))

View File

@@ -401,7 +401,7 @@ func GenerateChain(config *params.ChainConfig, parent *types.Block, engine conse
defer triedb.Close()
for i := 0; i < n; i++ {
statedb, err := state.New(parent.Root(), state.NewDatabaseWithNodeDB(db, triedb), nil)
statedb, err := state.New(parent.Root(), state.NewDatabaseWithNodeDB(db, triedb, true), nil)
if err != nil {
panic(err)
}
@@ -486,7 +486,7 @@ func (cm *chainMaker) makeHeader(parent *types.Block, state *state.StateDB, engi
if cm.config.Parlia != nil {
header.WithdrawalsHash = &types.EmptyWithdrawalsHash
}
if cm.config.Parlia == nil || cm.config.IsBohr(header.Number, header.Time) {
if cm.config.Parlia == nil {
header.ParentBeaconRoot = new(common.Hash)
}
}
@@ -621,10 +621,6 @@ func (cm *chainMaker) GetHighestVerifiedHeader() *types.Header {
panic("not supported")
}
func (cm *chainMaker) GetVerifiedBlockByHash(hash common.Hash) *types.Header {
return cm.GetHeaderByHash(hash)
}
func (cm *chainMaker) ChasingHead() *types.Header {
panic("not supported")
}

View File

@@ -365,10 +365,6 @@ func (r *mockDAHeaderReader) GetHighestVerifiedHeader() *types.Header {
panic("not supported")
}
func (r *mockDAHeaderReader) GetVerifiedBlockByHash(hash common.Hash) *types.Header {
panic("not supported")
}
func createMockDATx(config *params.ChainConfig, sidecar *types.BlobTxSidecar) *types.Transaction {
if sidecar == nil {
tx := &types.DynamicFeeTx{

View File

@@ -50,5 +50,3 @@ type ChainSideEvent struct {
}
type ChainHeadEvent struct{ Block *types.Block }
type HighestVerifiedBlockEvent struct{ Header *types.Header }

View File

@@ -121,19 +121,9 @@ func (f *ForkChoice) ReorgNeeded(current *types.Header, extern *types.Header) (b
if f.preserve != nil {
currentPreserve, externPreserve = f.preserve(current), f.preserve(extern)
}
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())
reorg = !currentPreserve && (externPreserve ||
extern.Time < current.Time ||
extern.Time == current.Time && f.rand.Float64() < 0.5)
}
return reorg, nil
}

View File

@@ -126,7 +126,10 @@ func hashAlloc(ga *types.GenesisAlloc, isVerkle bool) (common.Hash, error) {
}
// Create an ephemeral in-memory database for computing hash,
// all the derived states will be discarded to not pollute disk.
db := state.NewDatabaseWithConfig(rawdb.NewMemoryDatabase(), config)
db := state.NewDatabaseWithConfig(rawdb.NewMemoryDatabase(), config, true)
log.Info("genesis calc root hash use hash mode triedb")
db.SetVersion(0)
defer db.Release()
statedb, err := state.New(types.EmptyRootHash, db, nil)
if err != nil {
return common.Hash{}, err
@@ -154,7 +157,10 @@ func flushAlloc(ga *types.GenesisAlloc, db ethdb.Database, triedb *triedb.Databa
if triedbConfig != nil {
triedbConfig.NoTries = false
}
statedb, err := state.New(types.EmptyRootHash, state.NewDatabaseWithNodeDB(db, triedb), nil)
cachingdb := state.NewDatabaseWithNodeDB(db, triedb, true)
cachingdb.SetVersion(0)
defer cachingdb.Release()
statedb, err := state.New(types.EmptyRootHash, cachingdb, nil)
if err != nil {
return err
}
@@ -174,7 +180,7 @@ func flushAlloc(ga *types.GenesisAlloc, db ethdb.Database, triedb *triedb.Databa
return err
}
// Commit newly generated states into disk if it's not empty.
if root != types.EmptyRootHash {
if root != types.EmptyRootHash && triedb.Scheme() != rawdb.VersionScheme {
if err := triedb.Commit(root, true); err != nil {
return err
}
@@ -216,7 +222,6 @@ func (e *GenesisMismatchError) Error() string {
// ChainOverrides contains the changes to chain config
// Typically, these modifications involve hardforks that are not enabled on the BSC mainnet, intended for testing purposes.
type ChainOverrides struct {
OverridePassedForkTime *uint64
OverrideBohr *uint64
OverrideVerkle *uint64
}
@@ -244,15 +249,6 @@ func SetupGenesisBlockWithOverride(db ethdb.Database, triedb *triedb.Database, g
}
applyOverrides := func(config *params.ChainConfig) {
if config != nil {
if overrides != nil && overrides.OverridePassedForkTime != nil {
config.ShanghaiTime = overrides.OverridePassedForkTime
config.KeplerTime = overrides.OverridePassedForkTime
config.FeynmanTime = overrides.OverridePassedForkTime
config.FeynmanFixTime = overrides.OverridePassedForkTime
config.CancunTime = overrides.OverridePassedForkTime
config.HaberTime = overrides.OverridePassedForkTime
config.HaberFixTime = overrides.OverridePassedForkTime
}
if overrides != nil && overrides.OverrideBohr != nil {
config.BohrTime = overrides.OverrideBohr
}
@@ -454,7 +450,7 @@ func (g *Genesis) ToBlock() *types.Block {
// EIP-4788: The parentBeaconBlockRoot of the genesis block is always
// the zero hash. This is because the genesis block does not have a parent
// by definition.
if conf.Parlia == nil || conf.IsBohr(num, g.Timestamp) {
if conf.Parlia == nil {
head.ParentBeaconRoot = new(common.Hash)
}

View File

@@ -436,10 +436,6 @@ func (hc *HeaderChain) GetHighestVerifiedHeader() *types.Header {
return nil
}
func (hc *HeaderChain) GetVerifiedBlockByHash(hash common.Hash) *types.Header {
return hc.GetHeaderByHash(hash)
}
func (hc *HeaderChain) ChasingHead() *types.Header {
return nil
}

View File

@@ -46,6 +46,8 @@ const HashScheme = "hash"
// on extra state diffs to survive deep reorg.
const PathScheme = "path"
const VersionScheme = "version"
// hasher is used to compute the sha256 hash of the provided data.
type hasher struct{ sha crypto.KeccakState }
@@ -314,7 +316,7 @@ func ReadStateScheme(db ethdb.Reader) string {
// ValidateStateScheme used to check state scheme whether is valid.
// Valid state scheme: hash and path.
func ValidateStateScheme(stateScheme string) bool {
if stateScheme == HashScheme || stateScheme == PathScheme {
if stateScheme == HashScheme || stateScheme == PathScheme || stateScheme == VersionScheme {
return true
}
return false

View File

@@ -68,7 +68,6 @@ func newPrunedFreezer(datadir string, db ethdb.KeyValueStore, offset uint64) (*p
// repair init frozen , compatible disk-ancientdb and pruner-block-tool.
func (f *prunedfreezer) repair(datadir string) error {
offset := atomic.LoadUint64(&f.frozen)
// compatible freezer
minItems := uint64(math.MaxUint64)
for name, disableSnappy := range chainFreezerNoSnappy {
@@ -97,14 +96,19 @@ func (f *prunedfreezer) repair(datadir string) error {
table.Close()
}
// 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
// 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)
// 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 {
@@ -157,12 +161,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 (f *prunedfreezer) MigrateTable(kind string, convert convertLegacyFn) error {
func (db *prunedfreezer) MigrateTable(kind string, convert convertLegacyFn) error {
return errNotSupported
}
// AncientDatadir returns an error as we don't have a backing chain freezer.
func (f *prunedfreezer) AncientDatadir() (string, error) {
func (db *prunedfreezer) AncientDatadir() (string, error) {
return "", errNotSupported
}

View File

@@ -0,0 +1,521 @@
package state
import (
"errors"
"fmt"
"sync/atomic"
versa "github.com/bnb-chain/versioned-state-database"
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/common/lru"
"github.com/ethereum/go-ethereum/common/math"
"github.com/ethereum/go-ethereum/core/rawdb"
"github.com/ethereum/go-ethereum/core/types"
"github.com/ethereum/go-ethereum/crypto"
"github.com/ethereum/go-ethereum/ethdb"
"github.com/ethereum/go-ethereum/log"
"github.com/ethereum/go-ethereum/rlp"
"github.com/ethereum/go-ethereum/trie"
"github.com/ethereum/go-ethereum/trie/trienode"
"github.com/ethereum/go-ethereum/triedb"
)
const InvalidSateObjectVersion int64 = math.MinInt64
type cachingVersaDB struct {
version int64
triedb *triedb.Database
versionDB versa.Database
codeDB ethdb.KeyValueStore
codeSizeCache *lru.Cache[common.Hash, int]
codeCache *lru.SizeConstrainedCache[common.Hash, []byte]
accTree *VersaTree
state versa.StateHandler
root common.Hash
mode versa.StateMode
hasState atomic.Bool
debug *DebugVersionState
}
// NewVersaDatabase should be call by NewDatabaseWithNodeDB
// TODO:: NewDatabaseWithNodeDB should add mode param.
func NewVersaDatabase(db ethdb.Database, triedb *triedb.Database, mode versa.StateMode) Database {
return &cachingVersaDB{
triedb: triedb,
versionDB: triedb.VersaDB(),
codeDB: db,
codeSizeCache: lru.NewCache[common.Hash, int](codeSizeCacheSize),
codeCache: lru.NewSizeConstrainedCache[common.Hash, []byte](codeCacheSize),
mode: mode,
state: versa.ErrStateHandler,
}
}
func (cv *cachingVersaDB) Copy() Database {
cp := &cachingVersaDB{}
cp.codeCache = cv.codeCache
cp.codeSizeCache = cv.codeSizeCache
cp.triedb = cv.triedb
cp.versionDB = cv.versionDB
cp.codeDB = cv.codeDB
cp.mode = versa.S_RW // it is important
// TODO:: maybe add lock for cv.root
if cv.hasState.Load() {
_, err := cp.OpenTrie(cv.root)
if err != nil {
if cv.debug != nil {
cv.debug.OnError(fmt.Errorf("failed to open trie in copy caching versa db, error: %s", err.Error()))
}
return cp
}
}
return cp
}
// CopyTrie is used with Copy()
func (cv *cachingVersaDB) CopyTrie(tr Trie) Trie {
vtr, ok := tr.(*VersaTree)
if !ok {
panic("caching versa db copy non versa tree")
}
if vtr.accountTree {
if cv.accTree != nil {
if cv.accTree.root.Cmp(vtr.root) != 0 {
panic("copy acc trie mismatch")
}
return cv.accTree
}
tree, err := cv.OpenTrie(vtr.root)
if err != nil {
if cv.debug != nil {
cv.debug.OnError(fmt.Errorf("failed to open trie in copy versa trie, error: %s", err.Error()))
}
return nil
}
return tree
} else {
tree, err := cv.OpenStorageTrie(vtr.stateRoot, vtr.address, vtr.root, nil)
if err != nil {
if cv.debug != nil {
cv.debug.OnError(fmt.Errorf("failed to open storage trie in copy versa trie, error: %s", err.Error()))
}
return nil
}
return tree
}
return nil
}
func (cv *cachingVersaDB) HasState(root common.Hash) bool {
return cv.versionDB.HasState(root)
}
func (cv *cachingVersaDB) OpenTrie(root common.Hash) (Trie, error) {
if cv.hasState.Load() {
//TODO:: will change to log.Error after stabilization
panic("account tree has open")
}
// TODO:: if root tree, versa db should ignore check version, temp use -1
state, err := cv.versionDB.OpenState(cv.version, root, cv.mode)
if err != nil {
if cv.debug != nil {
cv.debug.OnError(fmt.Errorf("failed to open state, root:%s, error: %s", root.String(), err.Error()))
}
return nil, err
}
if cv.debug != nil {
cv.debug.OnOpenState(state)
}
handler, err := cv.versionDB.OpenTree(state, cv.version, common.Hash{}, root)
if err != nil {
if cv.debug != nil {
cv.debug.OnError(fmt.Errorf("failed to open account trie, root:%s, error: %s", root.String(), err.Error()))
}
return nil, err
}
tree := &VersaTree{
db: cv.versionDB,
handler: handler,
accountTree: true,
root: root,
mode: cv.mode,
debug: cv.debug,
}
cv.state = state
cv.hasState.Store(true) // if set, can't change
cv.accTree = tree
cv.root = root
if cv.debug != nil {
cv.debug.OnOpenTree(handler, common.Hash{}, common.Address{})
}
return tree, nil
}
func (cv *cachingVersaDB) OpenStorageTrie(stateRoot common.Hash, address common.Address, root common.Hash, _ Trie) (Trie, error) {
version, _, err := cv.accTree.getAccountWithVersion(address)
if err != nil {
return nil, err
}
return cv.openStorageTreeWithVersion(version, stateRoot, address, root)
}
func (cv *cachingVersaDB) openStorageTreeWithVersion(version int64, stateRoot common.Hash, address common.Address, root common.Hash) (Trie, error) {
if !cv.hasState.Load() {
//TODO:: will change to log.Error after stabilization
panic("open account tree, before open storage tree")
}
if cv.root.Cmp(stateRoot) != 0 {
panic(fmt.Sprintf("account root mismatch, on open storage tree, actual: %s, expect: %s", root.String(), cv.root.String()))
}
owner := crypto.Keccak256Hash(address.Bytes())
handler, err := cv.versionDB.OpenTree(cv.state, version, owner, root)
if err != nil {
if cv.debug != nil {
cv.debug.OnError(fmt.Errorf("failed to open storage trie, version: %d,stateRoot:%s, address:%s, root: %s, error: %s",
version, stateRoot.String(), address.String(), root.String(), err.Error()))
}
return nil, err
}
if cv.debug != nil {
cv.debug.OnOpenTree(handler, owner, address)
}
tree := &VersaTree{
db: cv.versionDB,
handler: handler,
version: version,
root: stateRoot,
stateRoot: root,
address: address,
mode: cv.mode,
debug: cv.debug,
}
return tree, nil
}
// Flush unique to versa
func (cv *cachingVersaDB) Flush() error {
err := cv.versionDB.Flush(cv.state)
if err != nil && cv.debug != nil {
cv.debug.OnError(fmt.Errorf("failed to flush state, version: %d, root:%s, mode:%d, error: %s",
cv.accTree.version, cv.accTree.root.String(), cv.accTree.mode, err.Error()))
}
return err
}
func (cv *cachingVersaDB) SetVersion(version int64) {
cv.version = version - 1
cv.debug = NewDebugVersionState(cv.codeDB, cv.versionDB)
cv.debug.Version = version
}
func (cv *cachingVersaDB) GetVersion() int64 {
return cv.version
}
// Release unique to versa
func (cv *cachingVersaDB) Release() error {
//log.Info("close state", "state info", cv.versionDB.ParseStateHandler(cv.state))
if cv.state != versa.ErrStateHandler {
if cv.debug != nil {
cv.debug.OnCloseState(cv.state)
}
if err := cv.versionDB.CloseState(cv.state); err != nil {
if cv.debug != nil {
cv.debug.OnError(fmt.Errorf("failed to close state in release, version: %d, root:%s, mode:%d, error: %s",
cv.accTree.version, cv.accTree.root.String(), cv.accTree.mode, err.Error()))
}
return err
}
cv.hasState.Store(false)
cv.accTree = nil
cv.state = versa.ErrStateHandler
cv.root = common.Hash{}
cv.debug = nil
}
return nil
}
func (cv *cachingVersaDB) Reset() {
if cv.state != versa.ErrStateHandler {
_ = cv.versionDB.CloseState(cv.state)
panic("close state in reset")
}
cv.hasState.Store(false)
cv.accTree = nil
cv.state = versa.ErrStateHandler
cv.root = common.Hash{}
}
func (cv *cachingVersaDB) HasTreeExpired(tr Trie) bool {
vtr, ok := tr.(*VersaTree)
if !ok {
panic("trie type mismatch")
}
return cv.versionDB.HasTreeExpired(vtr.handler)
}
func (cv *cachingVersaDB) Scheme() string {
return cv.triedb.Scheme()
}
func (cv *cachingVersaDB) ContractCode(addr common.Address, codeHash common.Hash) ([]byte, error) {
if cv.debug != nil {
cv.debug.OnGetCode(addr, codeHash)
}
code, _ := cv.codeCache.Get(codeHash)
if len(code) > 0 {
return code, nil
}
code = rawdb.ReadCode(cv.codeDB, codeHash)
if len(code) > 0 {
cv.codeCache.Add(codeHash, code)
cv.codeSizeCache.Add(codeHash, len(code))
return code, nil
}
return nil, errors.New("not found")
}
func (cv *cachingVersaDB) ContractCodeSize(addr common.Address, codeHash common.Hash) (int, error) {
if cached, ok := cv.codeSizeCache.Get(codeHash); ok {
return cached, nil
}
code, err := cv.ContractCode(addr, codeHash)
return len(code), err
}
func (cv *cachingVersaDB) ContractCodeWithPrefix(address common.Address, codeHash common.Hash) ([]byte, error) {
code, _ := cv.codeCache.Get(codeHash)
if len(code) > 0 {
return code, nil
}
code = rawdb.ReadCodeWithPrefix(cv.codeDB, codeHash)
if len(code) > 0 {
cv.codeCache.Add(codeHash, code)
cv.codeSizeCache.Add(codeHash, len(code))
return code, nil
}
return nil, errors.New("not found")
}
func (cv *cachingVersaDB) DiskDB() ethdb.KeyValueStore {
return cv.codeDB
}
func (cv *cachingVersaDB) TrieDB() *triedb.Database {
return cv.triedb
}
func (cv *cachingVersaDB) NoTries() bool {
// TODO:: not support fastnode
return false
}
type VersaTree struct {
db versa.Database
handler versa.TreeHandler
version int64
accountTree bool
debug *DebugVersionState
// TODO:: debugging, used for logging
stateRoot common.Hash
root common.Hash
address common.Address
mode versa.StateMode
}
func (vt *VersaTree) GetKey(key []byte) []byte {
_, val, err := vt.db.Get(vt.handler, key)
if err != nil {
log.Warn("failed to get key from version db")
}
return val
}
func (vt *VersaTree) GetAccount(address common.Address) (*types.StateAccount, error) {
_, res, err := vt.getAccountWithVersion(address)
return res, err
}
func (vt *VersaTree) getAccountWithVersion(address common.Address) (int64, *types.StateAccount, error) {
vt.CheckAccountTree()
ver, res, err := vt.db.Get(vt.handler, address.Bytes())
if res == nil || err != nil {
if err != nil && vt.debug != nil {
vt.debug.OnError(fmt.Errorf("failed to get account, root: %s, address: %s, error: %s",
vt.root.String(), address.String(), err.Error()))
}
return ver, nil, err
}
ret := new(types.StateAccount)
err = rlp.DecodeBytes(res, ret)
if err != nil {
if vt.debug != nil {
vt.debug.OnError(fmt.Errorf("failed to rlp decode account, root: %s, address: %s, error: %s",
vt.root.String(), address.String(), err.Error()))
}
}
if vt.debug != nil {
vt.debug.OnGetAccount(address, ret)
}
return ver, ret, err
}
func (vt *VersaTree) GetStorage(address common.Address, key []byte) ([]byte, error) {
if vt.address.Cmp(address) != 0 {
panic(fmt.Sprintf("address mismatch in get storage, expect: %s, actul: %s", vt.address.String(), address.String()))
}
vt.CheckStorageTree()
_, enc, err := vt.db.Get(vt.handler, key)
if err != nil || len(enc) == 0 {
if err != nil && vt.debug != nil {
vt.debug.OnError(fmt.Errorf("failed to get storage, root: %s, stateRoot: %s, address:%s, key: %s, error: %s",
vt.root.String(), vt.stateRoot.String(), address.String(), common.Bytes2Hex(key), err.Error()))
}
return nil, err
}
_, content, _, err := rlp.Split(enc)
if err != nil {
if vt.debug != nil {
vt.debug.OnError(fmt.Errorf("failed to rlp decode storage, root: %s, stateRoot: %s, address: %s, key: %s,error: %s",
vt.root.String(), vt.stateRoot.String(), address.String(), common.Bytes2Hex(key), err.Error()))
}
}
if vt.debug != nil {
vt.debug.OnGetStorage(vt.handler, address, key, content)
}
return content, err
}
func (vt *VersaTree) UpdateAccount(address common.Address, account *types.StateAccount) error {
vt.CheckAccountTree()
data, err := rlp.EncodeToBytes(account)
if err != nil {
if vt.debug != nil {
vt.debug.OnError(fmt.Errorf("failed to update account, root: %s, address: %s, account: %s, error: %s",
vt.root.String(), address.String(), account.String(), err.Error()))
}
return err
}
if vt.debug != nil {
vt.debug.OnUpdateAccount(address, account)
}
return vt.db.Put(vt.handler, address.Bytes(), data)
}
func (vt *VersaTree) UpdateStorage(address common.Address, key, value []byte) error {
if vt.address.Cmp(address) != 0 {
panic(fmt.Sprintf("address mismatch in get storage, expect: %s, actul: %s", vt.address.String(), address.String()))
}
vt.CheckStorageTree()
v, _ := rlp.EncodeToBytes(value)
err := vt.db.Put(vt.handler, key, v)
if err != nil {
if vt.debug != nil {
vt.debug.OnError(fmt.Errorf("failed to update storage, root: %s, stateRoot: %s, address: %s, key: %s, val: %s, error: %s",
vt.root.String(), vt.stateRoot.String(), address.String(), common.Bytes2Hex(key), common.Bytes2Hex(value), err.Error()))
}
}
if vt.debug != nil {
vt.debug.OnUpdateStorage(vt.handler, address, key, value)
}
return err
}
func (vt *VersaTree) DeleteAccount(address common.Address) error {
vt.CheckAccountTree()
err := vt.db.Delete(vt.handler, address.Bytes())
if err != nil {
if vt.debug != nil {
vt.debug.OnError(fmt.Errorf("failed to delete account, root: %s, address: %s, error: %s",
vt.root.String(), address.String(), err.Error()))
}
}
if vt.debug != nil {
vt.debug.OnDeleteAccount(address)
}
return err
}
func (vt *VersaTree) DeleteStorage(address common.Address, key []byte) error {
vt.CheckStorageTree()
err := vt.db.Delete(vt.handler, key)
if err != nil {
if vt.debug != nil {
vt.debug.OnError(fmt.Errorf("failed to delete storage, root: %s, stateRoot: %s, address: %s, key: %s, error: %s",
vt.root.String(), vt.stateRoot.String(), address.String(), common.Bytes2Hex(key), err.Error()))
}
}
if vt.debug != nil {
vt.debug.OnDeleteStorage(vt.handler, address, key)
}
return err
}
func (vt *VersaTree) UpdateContractCode(address common.Address, codeHash common.Hash, code []byte) error {
return nil
}
func (vt *VersaTree) Hash() common.Hash {
hash, err := vt.db.CalcRootHash(vt.handler)
if err != nil {
if vt.debug != nil {
vt.debug.OnError(fmt.Errorf("failed to calc root, root: %s, stateRoot%s, error:%s",
vt.root.String(), vt.stateRoot.String(), err.Error()))
}
}
if vt.debug != nil {
vt.debug.OnCalcHash(vt.address, hash)
}
return hash
}
func (vt *VersaTree) Commit(_ bool) (common.Hash, *trienode.NodeSet, error) {
hash, err := vt.db.Commit(vt.handler)
if err != nil {
if vt.debug != nil {
vt.debug.OnError(fmt.Errorf("failed to commit versa tree, root: %s, stateRoot: %s, error: %s",
vt.root.String(), vt.stateRoot.String(), err.Error()))
}
}
if vt.debug != nil {
vt.debug.OnCalcHash(vt.address, hash)
vt.debug.OnCommitTree(vt.address, vt.handler)
}
return hash, nil, err
}
func (vt *VersaTree) NodeIterator(startKey []byte) (trie.NodeIterator, error) {
panic("versa tree not support iterate")
return nil, nil
}
func (vt *VersaTree) Prove(key []byte, proofDb ethdb.KeyValueWriter) error {
panic("versa tree not support prove")
return nil
}
// TODO:: debug code, will be deleted after stabilization
func (vt *VersaTree) CheckAccountTree() {
if !vt.accountTree {
panic("sub tree can't operate account")
}
}
// TODO:: debug code, will be deleted after stabilization
func (vt *VersaTree) CheckStorageTree() {
if vt.accountTree {
panic("root tree can't operate storage")
}
}

View File

@@ -20,6 +20,7 @@ import (
"errors"
"fmt"
versa "github.com/bnb-chain/versioned-state-database"
"github.com/crate-crypto/go-ipa/banderwagon"
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/common/lru"
@@ -70,8 +71,33 @@ type Database interface {
// TrieDB returns the underlying trie database for managing trie nodes.
TrieDB() *triedb.Database
// Scheme returns triedb scheme, used to distinguish version triedb.
Scheme() string
// Flush used for version caching versa db to commit block state data.
Flush() error
// Release used for caching versa db to release resource.
Release() error
// Reset used for caching versa db to clean up meta data.
Reset()
// Copy used for caching versa db to copy db, main to transfer triedb with rw mode.
Copy() Database
// HasState returns the state data whether in the triedb.
HasState(root common.Hash) bool
// HasTreeExpired used for caching versa db, whether the state where the opened tree resides has been closed
HasTreeExpired(tr Trie) bool
// NoTries returns whether the database has tries storage.
NoTries() bool
SetVersion(version int64)
GetVersion() int64
}
// Trie is a Ethereum Merkle Patricia trie.
@@ -148,28 +174,43 @@ type Trie interface {
// concurrent use, but does not retain any recent trie nodes in memory. To keep some
// historical state in memory, use the NewDatabaseWithConfig constructor.
func NewDatabase(db ethdb.Database) Database {
return NewDatabaseWithConfig(db, nil)
return NewDatabaseWithConfig(db, nil, false)
}
// NewDatabaseWithConfig creates a backing store for state. The returned database
// is safe for concurrent use and retains a lot of collapsed RLP trie nodes in a
// large memory cache.
func NewDatabaseWithConfig(db ethdb.Database, config *triedb.Config) Database {
func NewDatabaseWithConfig(db ethdb.Database, config *triedb.Config, needCommit bool) Database {
noTries := config != nil && config.NoTries
triedb := triedb.NewDatabase(db, config)
if triedb.Scheme() == rawdb.VersionScheme {
if needCommit {
return NewVersaDatabase(db, triedb, versa.S_COMMIT)
}
return NewVersaDatabase(db, triedb, versa.S_RW)
}
return &cachingDB{
disk: db,
codeSizeCache: lru.NewCache[common.Hash, int](codeSizeCacheSize),
codeCache: lru.NewSizeConstrainedCache[common.Hash, []byte](codeCacheSize),
triedb: triedb.NewDatabase(db, config),
triedb: triedb,
noTries: noTries,
}
}
// NewDatabaseWithNodeDB creates a state database with an already initialized node database.
func NewDatabaseWithNodeDB(db ethdb.Database, triedb *triedb.Database) Database {
func NewDatabaseWithNodeDB(db ethdb.Database, triedb *triedb.Database, needCommit bool) Database {
noTries := triedb != nil && triedb.Config() != nil && triedb.Config().NoTries
if triedb.Scheme() == rawdb.VersionScheme {
if needCommit {
return NewVersaDatabase(db, triedb, versa.S_COMMIT)
}
return NewVersaDatabase(db, triedb, versa.S_RW)
}
return &cachingDB{
disk: db,
codeSizeCache: lru.NewCache[common.Hash, int](codeSizeCacheSize),
@@ -185,6 +226,8 @@ type cachingDB struct {
codeCache *lru.SizeConstrainedCache[common.Hash, []byte]
triedb *triedb.Database
noTries bool
debug *DebugHashState
}
// OpenTrie opens the main account trie at a specific root hash.
@@ -197,9 +240,22 @@ func (db *cachingDB) OpenTrie(root common.Hash) (Trie, error) {
}
tr, err := trie.NewStateTrie(trie.StateTrieID(root), db.triedb)
if err != nil {
if db.debug != nil {
db.debug.OnError(fmt.Errorf("failed to open tree, root: %s, error: %s", root.String(), err.Error()))
}
return nil, err
}
return tr, nil
ht := &HashTrie{
trie: tr,
root: root,
address: common.Address{},
owner: common.Hash{},
debug: db.debug,
}
if db.debug != nil {
db.debug.OnOpenTree(root, common.Hash{}, common.Address{})
}
return ht, nil
}
// OpenStorageTrie opens the storage trie of an account.
@@ -214,11 +270,27 @@ func (db *cachingDB) OpenStorageTrie(stateRoot common.Hash, address common.Addre
if db.triedb.IsVerkle() {
return self, nil
}
tr, err := trie.NewStateTrie(trie.StorageTrieID(stateRoot, crypto.Keccak256Hash(address.Bytes()), root), db.triedb)
owner := crypto.Keccak256Hash(address.Bytes())
tr, err := trie.NewStateTrie(trie.StorageTrieID(stateRoot, owner, root), db.triedb)
if err != nil {
if db.debug != nil {
db.debug.OnError(fmt.Errorf("failed to storage open tree, stateRoot: %s, address: %s, root: %s, error: %s",
stateRoot.String(), address.String(), root.String(), err.Error()))
}
return nil, err
}
return tr, nil
ht := &HashTrie{
trie: tr,
root: stateRoot,
statRoot: root,
address: address,
owner: owner,
debug: db.debug,
}
if db.debug != nil {
db.debug.OnOpenTree(root, owner, address)
}
return ht, nil
}
func (db *cachingDB) NoTries() bool {
@@ -235,6 +307,8 @@ func (db *cachingDB) CopyTrie(t Trie) Trie {
return t.Copy()
case *trie.EmptyTrie:
return t.Copy()
case *HashTrie:
return db.CopyTrie(t.trie)
default:
panic(fmt.Errorf("unknown trie type %T", t))
}
@@ -242,6 +316,9 @@ func (db *cachingDB) CopyTrie(t Trie) Trie {
// ContractCode retrieves a particular contract's code.
func (db *cachingDB) ContractCode(address common.Address, codeHash common.Hash) ([]byte, error) {
if db.debug != nil {
db.debug.OnGetCode(address, codeHash)
}
code, _ := db.codeCache.Get(codeHash)
if len(code) > 0 {
return code, nil
@@ -290,3 +367,178 @@ func (db *cachingDB) DiskDB() ethdb.KeyValueStore {
func (db *cachingDB) TrieDB() *triedb.Database {
return db.triedb
}
func (db *cachingDB) Reset() {
return
}
func (db *cachingDB) Scheme() string {
return db.triedb.Scheme()
}
func (db *cachingDB) Flush() error {
return nil
}
func (db *cachingDB) Release() error {
db.debug.flush()
db.debug = nil
return nil
}
func (db *cachingDB) SetVersion(version int64) {
db.debug = NewDebugHashState(db.disk)
db.debug.Version = version
}
func (db *cachingDB) GetVersion() int64 {
return db.debug.Version
}
func (db *cachingDB) Copy() Database {
return db
}
func (db *cachingDB) HasState(root common.Hash) bool {
_, err := db.OpenTrie(root)
return err == nil
}
func (db *cachingDB) HasTreeExpired(_ Trie) bool {
return false
}
type HashTrie struct {
trie Trie
root common.Hash
statRoot common.Hash
address common.Address
owner common.Hash
debug *DebugHashState
}
func (ht *HashTrie) GetKey(key []byte) []byte {
return ht.trie.GetKey(key)
}
func (ht *HashTrie) GetAccount(address common.Address) (*types.StateAccount, error) {
acc, err := ht.trie.GetAccount(address)
if err != nil {
if ht.debug != nil {
ht.debug.OnError(fmt.Errorf("failed to get account, address: %s, error: %s", address.String(), err.Error()))
}
return nil, err
}
if ht.debug != nil {
ht.debug.OnGetAccount(address, acc)
}
return acc, nil
}
func (ht *HashTrie) GetStorage(addr common.Address, key []byte) ([]byte, error) {
val, err := ht.trie.GetStorage(addr, key)
if err != nil {
if ht.debug != nil {
ht.debug.OnError(fmt.Errorf("failed to get storage, address: %s, error: %s", addr.String(), err.Error()))
}
return val, err
}
if ht.debug != nil {
ht.debug.OnGetStorage(addr, key, val)
}
return val, err
}
func (ht *HashTrie) UpdateAccount(address common.Address, account *types.StateAccount) error {
err := ht.trie.UpdateAccount(address, account)
if err != nil {
if ht.debug != nil {
ht.debug.OnError(fmt.Errorf("failed to update account, address: %s, account: %s, error: %s",
address.String(), account.String(), err.Error()))
}
return err
}
if ht.debug != nil {
ht.debug.OnUpdateAccount(address, account)
}
return nil
}
func (ht *HashTrie) UpdateStorage(addr common.Address, key, value []byte) error {
err := ht.trie.UpdateStorage(addr, key, value)
if err != nil {
if ht.debug != nil {
ht.debug.OnError(fmt.Errorf("failed to update storage, address: %s, key: %s, val: %s, error: %s",
addr.String(), common.Bytes2Hex(key), common.Bytes2Hex(value), err.Error()))
}
return err
}
if ht.debug != nil {
ht.debug.OnUpdateStorage(addr, key, value)
}
return nil
}
func (ht *HashTrie) DeleteAccount(address common.Address) error {
err := ht.trie.DeleteAccount(address)
if err != nil {
if ht.debug != nil {
ht.debug.OnError(fmt.Errorf("failed to delete account, address: %s, error: %s", address.String(), err.Error()))
}
return err
}
if ht.debug != nil {
ht.debug.OnDeleteAccount(address)
}
return nil
}
func (ht *HashTrie) DeleteStorage(addr common.Address, key []byte) error {
err := ht.trie.DeleteStorage(addr, key)
if err != nil {
if ht.debug != nil {
ht.debug.OnError(fmt.Errorf("failed to update storage, address: %s, key: %s, error: %s",
addr.String(), common.Bytes2Hex(key), err.Error()))
}
return err
}
if ht.debug != nil {
ht.debug.OnDeleteStorage(addr, key)
}
return nil
}
func (ht *HashTrie) UpdateContractCode(address common.Address, codeHash common.Hash, code []byte) error {
return ht.trie.UpdateContractCode(address, codeHash, code)
}
func (ht *HashTrie) Hash() common.Hash {
root := ht.trie.Hash()
if ht.debug != nil {
ht.debug.OnCalcHash(ht.address, root)
}
return root
}
func (ht *HashTrie) Commit(collectLeaf bool) (common.Hash, *trienode.NodeSet, error) {
hash, set, err := ht.trie.Commit(collectLeaf)
if err != nil {
ht.debug.OnError(fmt.Errorf("failed to commit tree, address: %s, error: %s",
ht.address.String(), err.Error()))
return hash, set, err
}
if ht.debug != nil {
ht.debug.OnCalcHash(ht.address, hash)
ht.debug.OnCommitTree(ht.address, hash)
}
return hash, set, nil
}
func (ht *HashTrie) NodeIterator(startKey []byte) (trie.NodeIterator, error) {
return ht.trie.NodeIterator(startKey)
}
func (ht *HashTrie) Prove(key []byte, proofDb ethdb.KeyValueWriter) error {
return ht.trie.Prove(key, proofDb)
}

View File

@@ -161,7 +161,7 @@ func (s *StateDB) DumpToCollector(c DumpCollector, conf *DumpConfig) (nextKey []
address = &addr
account.Address = address
}
obj := newObject(s, addr, &data)
obj := newObject(s, addr, &data, InvalidSateObjectVersion)
if !conf.SkipCode {
account.Code = obj.Code()
}

View File

@@ -232,6 +232,7 @@ func pruneAll(maindb ethdb.Database, g *core.Genesis) error {
}
log.Info("Database compaction finished", "elapsed", common.PrettyDuration(time.Since(cstart)))
}
// pruner should be not used to version db
statedb, _ := state.New(common.Hash{}, state.NewDatabase(maindb), nil)
for addr, account := range g.Alloc {
statedb.AddBalance(addr, uint256.MustFromBig(account.Balance))

View File

@@ -24,6 +24,7 @@ import (
"time"
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/core/rawdb"
"github.com/ethereum/go-ethereum/core/types"
"github.com/ethereum/go-ethereum/crypto"
"github.com/ethereum/go-ethereum/metrics"
@@ -63,6 +64,7 @@ func (s Storage) Copy() Storage {
// - Finally, call commit to return the changes of storage trie and update account data.
type stateObject struct {
db *StateDB
version int64
address common.Address // address of ethereum account
addrHash common.Hash // hash of ethereum address of the account
origin *types.StateAccount // Account original data without any change applied, nil means it was not existent
@@ -99,7 +101,7 @@ func (s *stateObject) empty() bool {
}
// newObject creates a state object.
func newObject(db *StateDB, address common.Address, acct *types.StateAccount) *stateObject {
func newObject(db *StateDB, address common.Address, acct *types.StateAccount, version int64) *stateObject {
var (
origin = acct
created = acct == nil // true if the account was not existent
@@ -112,9 +114,9 @@ func newObject(db *StateDB, address common.Address, acct *types.StateAccount) *s
if db != nil && db.storagePool != nil {
storageMap = db.GetStorage(address)
}
return &stateObject{
db: db,
version: version,
address: address,
addrHash: crypto.Keccak256Hash(address[:]),
origin: origin,
@@ -158,8 +160,18 @@ func (s *stateObject) getTrie() (Trie, error) {
// s.trie = s.db.prefetcher.trie(s.addrHash, s.data.Root)
// }
// if s.trie == nil {
tr, err := s.db.db.OpenStorageTrie(s.db.originalRoot, s.address, s.data.Root, s.db.trie)
var (
tr Trie
err error
)
if s.version == InvalidSateObjectVersion {
tr, err = s.db.db.OpenStorageTrie(s.db.originalRoot, s.address, s.data.Root, s.db.trie)
} else {
tr, err = s.db.db.(*cachingVersaDB).openStorageTreeWithVersion(s.version, s.db.originalRoot, s.address, s.data.Root)
}
if err != nil {
panic(fmt.Sprintf("open storage storage failed, root version: %d, storage version: %d, addrss: %s, storage root: %s, error: %s", s.db.db.GetVersion(), s.version, s.address.String(), s.data.Root.String(), err.Error()))
return nil, err
}
s.trie = tr
@@ -229,6 +241,7 @@ func (s *stateObject) GetCommittedState(key common.Hash) common.Hash {
value common.Hash
)
if s.db.snap != nil {
panic("snap is not nil")
start := time.Now()
enc, err = s.db.snap.Storage(s.addrHash, crypto.Keccak256Hash(key.Bytes()))
if metrics.EnabledExpensive {
@@ -302,6 +315,30 @@ func (s *stateObject) finalise(prefetch bool) {
}
}
func (s *stateObject) IsContractAccount() bool {
return s.data.Root.Cmp(types.EmptyRootHash) != 0 ||
bytes.Compare(s.data.CodeHash, types.EmptyCodeHash.Bytes()) != 0
}
func (s *stateObject) IsAccountChanged() bool {
if s.origin == nil {
return true
}
if s.data.Nonce != s.origin.Nonce {
return true
}
if s.data.Balance.Cmp(s.origin.Balance) != 0 {
return true
}
if s.data.Root.Cmp(s.origin.Root) != 0 {
return true
}
if bytes.Compare(s.data.CodeHash, s.origin.CodeHash) != 0 {
return true
}
return false
}
// updateTrie is responsible for persisting cached storage changes into the
// object's storage trie. In case the storage trie is not yet loaded, this
// function will load the trie automatically. If any issues arise during the
@@ -312,10 +349,28 @@ func (s *stateObject) updateTrie() (Trie, error) {
// Make sure all dirty slots are finalized into the pending storage area
s.finalise(false)
// fix 33740 blocks issue, add 1002 contract balance, but not update 1002
// storage tree, the case lead to 1002 account version mismatch with 1002
// storage tree version, occurs 53409 block open 1002 storage tree error.
if s.db.db.Scheme() == rawdb.VersionScheme {
if len(s.pendingStorage) == 0 {
// transferring balance to a contract or upgrading the code, but
// without updating the storage key, a commit is still required to
// increment the version number of the storage tree.
if !s.IsContractAccount() {
return s.trie, nil
}
//if !s.IsAccountChanged() {
// return s.trie, nil
//}
}
} else {
// Short circuit if nothing changed, don't bother with hashing anything
if len(s.pendingStorage) == 0 {
return s.trie, nil
}
}
// Track the amount of time wasted on updating the storage trie
if metrics.EnabledExpensive {
defer func(start time.Time) {
@@ -511,6 +566,7 @@ func (s *stateObject) setBalance(amount *uint256.Int) {
}
func (s *stateObject) deepCopy(db *StateDB) *stateObject {
//TODO:: debug code, deleted in the future
obj := &stateObject{
db: db,
address: s.address,

View File

@@ -166,12 +166,18 @@ func NewWithSharedPool(root common.Hash, db Database, snaps *snapshot.Tree) (*St
if err != nil {
return nil, err
}
statedb.storagePool = NewStoragePool()
//statedb.storagePool = NewStoragePool()
return statedb, nil
}
// New creates a new state from a given trie.
func New(root common.Hash, db Database, snaps *snapshot.Tree) (*StateDB, error) {
if db.Scheme() == rawdb.VersionScheme && snaps != nil {
panic("statedb snapshot must be nil in version db.")
}
// clean up previous traces
db.Reset()
sdb := &StateDB{
db: db,
originalRoot: root,
@@ -196,6 +202,7 @@ func New(root common.Hash, db Database, snaps *snapshot.Tree) (*StateDB, error)
sdb.snap = sdb.snaps.Snapshot(root)
}
// It should only one to open account tree
tr, err := db.OpenTrie(root)
// return error when 1. failed to open trie and 2. the snap is nil or the snap is not nil and done verification
if err != nil && (sdb.snap == nil || sdb.snap.Verified()) {
@@ -222,6 +229,9 @@ func (s *StateDB) TransferPrefetcher(prev *StateDB) {
prev.prefetcherLock.Lock()
fetcher = prev.prefetcher
prev.prefetcher = nil
if fetcher != nil {
panic("TransferPrefetcher is not nil")
}
prev.prefetcherLock.Unlock()
s.prefetcherLock.Lock()
@@ -243,6 +253,8 @@ func (s *StateDB) StartPrefetcher(namespace string) {
s.prefetcher = nil
}
if s.snap != nil {
// TODO:: debug code , will be deleted in the future
panic("snapshot is not nill, will start prefetch")
parent := s.snap.Parent()
if parent != nil {
s.prefetcher = newTriePrefetcher(s.db, s.originalRoot, parent.Root(), namespace)
@@ -305,6 +317,7 @@ func (s *StateDB) EnablePipeCommit() {
if s.snap != nil && s.snaps.Layers() > 1 {
// after big merge, disable pipeCommit for now,
// because `s.db.TrieDB().Update` should be called after `s.trie.Commit(true)`
panic("snapshot is not nil")
s.pipeCommit = false
}
}
@@ -323,6 +336,8 @@ func (s *StateDB) MarkFullProcessed() {
func (s *StateDB) setError(err error) {
if s.dbErr == nil {
s.dbErr = err
} else {
s.dbErr = fmt.Errorf(s.dbErr.Error()+", ", err.Error())
}
}
@@ -338,6 +353,8 @@ func (s *StateDB) Error() error {
// Not thread safe
func (s *StateDB) Trie() (Trie, error) {
if s.trie == nil {
// TODO:: debug code, will be deleted in the future.
panic("state get trie is nil")
err := s.WaitPipeVerification()
if err != nil {
return nil, err
@@ -719,6 +736,7 @@ func (s *StateDB) getDeletedStateObject(addr common.Address) *stateObject {
// If no live objects are available, attempt to use snapshots
var data *types.StateAccount
if s.snap != nil {
panic("snapshot is not nil")
start := time.Now()
acc, err := s.snap.Account(crypto.HashData(s.hasher, addr.Bytes()))
if metrics.EnabledExpensive {
@@ -743,9 +761,12 @@ func (s *StateDB) getDeletedStateObject(addr common.Address) *stateObject {
}
}
version := InvalidSateObjectVersion
// If snapshot unavailable or reading from it failed, load from the database
if data == nil {
if s.trie == nil {
// TODO:: debug code, will be deleted in the future.
panic("getDeletedStateObject get trie is nil")
tr, err := s.db.OpenTrie(s.originalRoot)
if err != nil {
s.setError(errors.New("failed to open trie tree"))
@@ -755,7 +776,12 @@ func (s *StateDB) getDeletedStateObject(addr common.Address) *stateObject {
}
start := time.Now()
var err error
if vtr, ok := s.trie.(*VersaTree); ok {
version, data, err = vtr.getAccountWithVersion(addr)
} else {
data, err = s.trie.GetAccount(addr)
}
if metrics.EnabledExpensive {
s.AccountReads += time.Since(start)
}
@@ -768,7 +794,7 @@ func (s *StateDB) getDeletedStateObject(addr common.Address) *stateObject {
}
}
// Insert into the live set
obj := newObject(s, addr, data)
obj := newObject(s, addr, data, version)
s.setStateObject(obj)
return obj
}
@@ -790,7 +816,7 @@ func (s *StateDB) getOrNewStateObject(addr common.Address) *stateObject {
// the given address, it is overwritten and returned as the second return value.
func (s *StateDB) createObject(addr common.Address) (newobj, prev *stateObject) {
prev = s.getDeletedStateObject(addr) // Note, prev might have been deleted, we need that!
newobj = newObject(s, addr, nil)
newobj = newObject(s, addr, nil, InvalidSateObjectVersion)
if prev == nil {
s.journal.append(createObjectChange{account: &addr})
} else {
@@ -859,10 +885,12 @@ func (s *StateDB) CopyDoPrefetch() *StateDB {
// If doPrefetch is true, it tries to reuse the prefetcher, the copied StateDB will do active trie prefetch.
// otherwise, just do inactive copy trie prefetcher.
func (s *StateDB) copyInternal(doPrefetch bool) *StateDB {
db := s.db.Copy()
tr := db.CopyTrie(s.trie)
// Copy all the basic fields, initialize the memory ones
state := &StateDB{
db: s.db,
trie: s.db.CopyTrie(s.trie),
db: db,
trie: tr,
// noTrie:s.noTrie,
// expectedRoot: s.expectedRoot,
// stateRoot: s.stateRoot,
@@ -1003,6 +1031,7 @@ func (s *StateDB) GetRefund() uint64 {
func (s *StateDB) WaitPipeVerification() error {
// Need to wait for the parent trie to commit
if s.snap != nil {
panic("snapshot is not nil")
if valid := s.snap.WaitAndGetVerifyRes(); !valid {
return errors.New("verification on parent snap failed")
}
@@ -1108,6 +1137,7 @@ func (s *StateDB) PopulateSnapAccountAndStorage() {
for addr := range s.stateObjectsPending {
if obj := s.stateObjects[addr]; !obj.deleted {
if s.snap != nil {
panic("snapshot is not nil")
s.populateSnapStorage(obj)
s.accounts[obj.addrHash] = types.SlimAccountRLP(obj.data)
}
@@ -1210,6 +1240,8 @@ func (s *StateDB) StateIntermediateRoot() common.Hash {
}
}
if s.trie == nil {
// TODO:: debug code, will be deleted in the future.
panic("StateIntermediateRoot get trie is nil")
tr, err := s.db.OpenTrie(s.originalRoot)
if err != nil {
panic(fmt.Sprintf("failed to open trie tree %s", s.originalRoot))
@@ -1369,6 +1401,7 @@ func (s *StateDB) deleteStorage(addr common.Address, addrHash common.Hash, root
// generated, or it's internally corrupted. Fallback to the slow
// one just in case.
if s.snap != nil {
panic("snapshot is not nil")
aborted, size, slots, nodes, err = s.fastDeleteStorage(addrHash, root)
}
if s.snap == nil || err != nil {
@@ -1422,7 +1455,8 @@ func (s *StateDB) handleDestruction(nodes *trienode.MergedNodeSet) (map[common.A
// considerable time and storage deletion isn't supported in hash mode, thus
// preemptively avoiding unnecessary expenses.
incomplete := make(map[common.Address]struct{})
if s.db.TrieDB().Scheme() == rawdb.HashScheme {
// Only pbss need handler incomplete destruction storage trie
if s.db.TrieDB().Scheme() != rawdb.PathScheme {
return incomplete, nil
}
for addr, prev := range s.stateObjectsDestruct {
@@ -1498,6 +1532,7 @@ func (s *StateDB) Commit(block uint64, failPostCommitFunc func(), postCommitFunc
)
if s.snap != nil {
panic("snapshot is not nil")
diffLayer = &types.DiffLayer{}
}
if s.pipeCommit {
@@ -1613,6 +1648,20 @@ func (s *StateDB) Commit(block uint64, failPostCommitFunc func(), postCommitFunc
origin = types.EmptyRootHash
}
if s.db.Scheme() == rawdb.VersionScheme {
// flush and release will occur regardless of whether the root changes
start := time.Now()
if err := s.db.Flush(); err != nil {
return err
}
if err := s.db.Release(); err != nil {
return err
}
s.originalRoot = root
if metrics.EnabledExpensive {
s.TrieDBCommits += time.Since(start)
}
} else {
if root != origin {
start := time.Now()
set := triestate.New(s.accountsOrigin, s.storagesOrigin, incomplete)
@@ -1628,6 +1677,7 @@ func (s *StateDB) Commit(block uint64, failPostCommitFunc func(), postCommitFunc
}
}
}
}
for _, postFunc := range postCommitFuncs {
err := postFunc()
@@ -1663,8 +1713,21 @@ func (s *StateDB) Commit(block uint64, failPostCommitFunc func(), postCommitFunc
// Write any contract code associated with the state object
if obj.code != nil && obj.dirtyCode {
rawdb.WriteCode(codeWriter, common.BytesToHash(obj.CodeHash()), obj.code)
switch d := s.db.(type) {
case *cachingVersaDB:
if d.debug != nil {
d.debug.OnUpdateCode(obj.address, common.BytesToHash(obj.CodeHash()))
}
case *cachingDB:
if d.debug != nil {
d.debug.OnUpdateCode(obj.address, common.BytesToHash(obj.CodeHash()))
}
default:
panic("caching db type error")
}
obj.dirtyCode = false
if s.snap != nil {
panic("snapshot is not nil")
diffLayer.Codes = append(diffLayer.Codes, types.DiffCode{
Hash: common.BytesToHash(obj.CodeHash()),
Code: obj.code,
@@ -1690,6 +1753,7 @@ func (s *StateDB) Commit(block uint64, failPostCommitFunc func(), postCommitFunc
func() error {
// If snapshotting is enabled, update the snapshot tree with this new version
if s.snap != nil {
panic("snapshot is not nil")
if metrics.EnabledExpensive {
defer func(start time.Time) { s.SnapshotCommits += time.Since(start) }(time.Now())
}

View File

@@ -0,0 +1,207 @@
package state
import (
"encoding/json"
"fmt"
"github.com/ethereum/go-ethereum/common"
)
var (
VersionState = "version"
HashState = "hash"
)
type DebugStateDiff struct {
DiffUpdateAccount map[string][]*VersaAccountInfo
DiffDeleteAccount map[string][]common.Address
DiffUpdateStorage map[string][]*VersaStorageInfo
DiffDeleteStorage map[string][]*VersaStorageInfo
DiffCalcHash map[string]map[common.Address]common.Hash
OwnerMap map[common.Address]common.Hash
DiffErrs map[string][]string
}
func (df *DebugStateDiff) diffUpdateAccount(vs []*VersaAccountInfo, hs []*VersaAccountInfo) {
count := len(vs)
if count > len(hs) {
count = len(hs)
}
idx := 0
for ; idx < count; idx++ {
if vs[idx].Address.Cmp(hs[idx].Address) != 0 {
break
}
if vs[idx].Account.Nonce != hs[idx].Account.Nonce {
break
}
if vs[idx].Account.Balance.Cmp(hs[idx].Account.Balance) != 0 {
break
}
if vs[idx].Account.Root.Cmp(hs[idx].Account.Root) != 0 {
break
}
if common.BytesToHash(vs[idx].Account.CodeHash).Cmp(common.BytesToHash(hs[idx].Account.CodeHash)) != 0 {
break
}
}
if idx < len(vs) {
df.DiffUpdateAccount[VersionState] = vs[idx:]
}
if idx < len(hs) {
df.DiffUpdateAccount[HashState] = hs[idx:]
}
return
}
func (df *DebugStateDiff) diffDeleteAccount(vs []common.Address, hs []common.Address) {
count := len(vs)
if count > len(hs) {
count = len(hs)
}
idx := 0
for ; idx < count; idx++ {
if vs[idx].Cmp(hs[idx]) != 0 {
break
}
}
if idx < len(vs) {
df.DiffDeleteAccount[VersionState] = vs[idx:]
}
if idx < len(hs) {
df.DiffDeleteAccount[HashState] = hs[idx:]
}
return
}
func (df *DebugStateDiff) diffUpdateStorage(vs []*VersaStorageInfo, hs []*VersaStorageInfo) {
count := len(vs)
if count > len(hs) {
count = len(hs)
}
idx := 0
for ; idx < count; idx++ {
if vs[idx].Address.Cmp(hs[idx].Address) != 0 {
break
}
if vs[idx].Key != hs[idx].Key {
break
}
if vs[idx].Val != hs[idx].Val {
break
}
}
if idx < len(vs) {
df.DiffUpdateStorage[VersionState] = vs[idx:]
}
if idx < len(hs) {
df.DiffUpdateStorage[HashState] = hs[idx:]
}
return
}
func (df *DebugStateDiff) diffDeleteStorage(vs []*VersaStorageInfo, hs []*VersaStorageInfo) {
count := len(vs)
if count > len(hs) {
count = len(hs)
}
idx := 0
for ; idx < count; idx++ {
if vs[idx].Address.Cmp(hs[idx].Address) != 0 {
break
}
if vs[idx].Key != hs[idx].Key {
break
}
}
if idx < len(vs) {
df.DiffDeleteStorage[VersionState] = vs[idx:]
}
if idx < len(hs) {
df.DiffDeleteStorage[HashState] = hs[idx:]
}
return
}
func (df *DebugStateDiff) diffCalcHash(vs map[common.Address]common.Hash, hs map[common.Address]common.Hash) {
record := make(map[common.Address]struct{})
for address, vch := range vs {
record[address] = struct{}{}
hch, ok := hs[address]
if !ok {
df.DiffCalcHash[VersionState][address] = vch
}
if vch.Cmp(hch) != 0 {
df.DiffCalcHash[VersionState][address] = vch
df.DiffCalcHash[HashState][address] = hch
}
}
for address := range record {
delete(vs, address)
delete(hs, address)
}
for address, hash := range vs {
df.DiffCalcHash[VersionState][address] = hash
}
for address, hash := range hs {
df.DiffCalcHash[HashState][address] = hash
}
}
func GenerateDebugStateDiff(vs *DebugVersionState, hs *DebugHashState) string {
diff := &DebugStateDiff{
DiffUpdateAccount: make(map[string][]*VersaAccountInfo),
DiffDeleteAccount: make(map[string][]common.Address),
DiffUpdateStorage: make(map[string][]*VersaStorageInfo),
DiffDeleteStorage: make(map[string][]*VersaStorageInfo),
DiffCalcHash: make(map[string]map[common.Address]common.Hash),
OwnerMap: make(map[common.Address]common.Hash),
DiffErrs: make(map[string][]string),
}
diff.DiffUpdateAccount[VersionState] = make([]*VersaAccountInfo, 0)
diff.DiffUpdateAccount[HashState] = make([]*VersaAccountInfo, 0)
diff.DiffDeleteAccount[VersionState] = make([]common.Address, 0)
diff.DiffDeleteAccount[HashState] = make([]common.Address, 0)
diff.DiffUpdateStorage[VersionState] = make([]*VersaStorageInfo, 0)
diff.DiffUpdateStorage[HashState] = make([]*VersaStorageInfo, 0)
diff.DiffDeleteStorage[VersionState] = make([]*VersaStorageInfo, 0)
diff.DiffDeleteStorage[HashState] = make([]*VersaStorageInfo, 0)
diff.DiffCalcHash[VersionState] = make(map[common.Address]common.Hash)
diff.DiffCalcHash[HashState] = make(map[common.Address]common.Hash)
diff.DiffErrs[VersionState] = make([]string, 0)
diff.DiffErrs[HashState] = make([]string, 0)
diff.diffUpdateAccount(vs.UpdateAccounts, hs.UpdateAccounts)
diff.diffDeleteAccount(vs.DeleteAccounts, hs.DeleteAccounts)
diff.diffUpdateStorage(vs.UpdateStorage, hs.UpdateStorage)
diff.diffDeleteStorage(vs.DeleteStorage, hs.DeleteStorage)
diff.diffCalcHash(vs.CalcHash, hs.CalcHash)
for address, _ := range diff.DiffCalcHash[HashState] {
diff.OwnerMap[address] = hs.StorageAddr2Owner[address]
}
for address, _ := range diff.DiffCalcHash[VersionState] {
diff.OwnerMap[address] = vs.StorageAddr2Owner[address]
}
if len(vs.Errs) != 0 || len(hs.Errs) != 0 {
diff.DiffErrs[VersionState] = vs.Errs
diff.DiffErrs[HashState] = hs.Errs
}
data, err := json.Marshal(diff)
if err != nil {
panic(fmt.Sprintf("failed to json encode debug info, err: %s", err.Error()))
}
return string(data)
}

View File

@@ -0,0 +1,216 @@
package state
import (
"encoding/json"
"fmt"
"sort"
"strconv"
"sync"
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/core/types"
"github.com/ethereum/go-ethereum/ethdb"
)
type DebugHashState struct {
disk ethdb.KeyValueStore
lock sync.Mutex
Version int64
AccessTrees map[common.Address][]common.Hash
CommitTrees map[common.Address][]common.Hash
CalcHash map[common.Address]common.Hash
GetAccounts []*VersaAccountInfo
UpdateAccounts []*VersaAccountInfo
DeleteAccounts []common.Address
GetStorage []*VersaStorageInfo
UpdateStorage []*VersaStorageInfo
DeleteStorage []*VersaStorageInfo
StorageAddr2Owner map[common.Address]common.Hash
GetCode map[common.Address][]common.Hash
UpdateCode map[common.Address][]common.Hash
Errs []string
}
func NewDebugHashState(disk ethdb.KeyValueStore) *DebugHashState {
return &DebugHashState{
disk: disk,
AccessTrees: make(map[common.Address][]common.Hash),
CommitTrees: make(map[common.Address][]common.Hash),
CalcHash: make(map[common.Address]common.Hash),
GetAccounts: make([]*VersaAccountInfo, 0),
UpdateAccounts: make([]*VersaAccountInfo, 0),
DeleteAccounts: make([]common.Address, 0),
GetStorage: make([]*VersaStorageInfo, 0),
UpdateStorage: make([]*VersaStorageInfo, 0),
DeleteStorage: make([]*VersaStorageInfo, 0),
StorageAddr2Owner: make(map[common.Address]common.Hash),
GetCode: make(map[common.Address][]common.Hash),
UpdateCode: make(map[common.Address][]common.Hash),
Errs: make([]string, 0),
}
}
func (hs *DebugHashState) OnOpenTree(root common.Hash, owner common.Hash, address common.Address) {
hs.lock.Lock()
defer hs.lock.Unlock()
if _, ok := hs.AccessTrees[address]; !ok {
hs.AccessTrees[address] = make([]common.Hash, 0)
}
hs.AccessTrees[address] = append(hs.AccessTrees[address], root)
hs.StorageAddr2Owner[address] = owner
}
func (hs *DebugHashState) OnGetAccount(addr common.Address, acc *types.StateAccount) {
hs.lock.Lock()
defer hs.lock.Unlock()
hs.GetAccounts = append(hs.GetAccounts, &VersaAccountInfo{
Address: addr,
Account: acc,
})
}
func (hs *DebugHashState) OnUpdateAccount(addr common.Address, acc *types.StateAccount) {
hs.lock.Lock()
defer hs.lock.Unlock()
hs.UpdateAccounts = append(hs.UpdateAccounts, &VersaAccountInfo{
Address: addr,
Account: acc,
})
}
func (hs *DebugHashState) OnDeleteAccount(address common.Address) {
hs.lock.Lock()
defer hs.lock.Unlock()
hs.DeleteAccounts = append(hs.DeleteAccounts, address)
}
func (hs *DebugHashState) OnGetStorage(address common.Address, key []byte, val []byte) {
hs.lock.Lock()
defer hs.lock.Unlock()
hs.GetStorage = append(hs.GetStorage, &VersaStorageInfo{
Address: address,
Key: common.Bytes2Hex(key),
Val: common.Bytes2Hex(val),
})
}
func (hs *DebugHashState) OnUpdateStorage(address common.Address, key []byte, val []byte) {
hs.lock.Lock()
defer hs.lock.Unlock()
hs.UpdateStorage = append(hs.UpdateStorage, &VersaStorageInfo{
Address: address,
Key: common.Bytes2Hex(key),
Val: common.Bytes2Hex(val),
})
}
func (hs *DebugHashState) OnDeleteStorage(address common.Address, key []byte) {
hs.lock.Lock()
defer hs.lock.Unlock()
hs.DeleteStorage = append(hs.DeleteStorage, &VersaStorageInfo{
Address: address,
Key: common.Bytes2Hex(key),
})
}
func (hs *DebugHashState) OnGetCode(addr common.Address, codeHash common.Hash) {
hs.lock.Lock()
defer hs.lock.Unlock()
if _, ok := hs.GetCode[addr]; !ok {
hs.GetCode[addr] = make([]common.Hash, 0)
}
hs.GetCode[addr] = append(hs.GetCode[addr], codeHash)
}
func (hs *DebugHashState) OnUpdateCode(addr common.Address, codeHash common.Hash) {
hs.lock.Lock()
defer hs.lock.Unlock()
if _, ok := hs.UpdateCode[addr]; !ok {
hs.UpdateCode[addr] = make([]common.Hash, 0)
}
hs.UpdateCode[addr] = append(hs.UpdateCode[addr], codeHash)
}
func (hs *DebugHashState) OnCalcHash(addr common.Address, root common.Hash) {
hs.lock.Lock()
defer hs.lock.Unlock()
hs.CalcHash[addr] = root
}
func (hs *DebugHashState) OnCommitTree(addr common.Address, root common.Hash) {
hs.lock.Lock()
defer hs.lock.Unlock()
if _, ok := hs.CommitTrees[addr]; !ok {
hs.CommitTrees[addr] = make([]common.Hash, 0)
}
hs.CommitTrees[addr] = append(hs.CommitTrees[addr], root)
}
func (hs *DebugHashState) OnError(err error) {
hs.lock.Lock()
defer hs.lock.Unlock()
hs.Errs = append(hs.Errs, err.Error())
}
func (hs *DebugHashState) flush() {
hs.lock.Lock()
defer hs.lock.Unlock()
hs.sortItems()
data, err := json.Marshal(hs)
if err != nil {
panic(fmt.Sprintf("failed to json encode debug info, err: %s", err.Error()))
}
err = hs.disk.Put(DebugHashStateKey(hs.Version), data)
if err != nil {
panic(fmt.Sprintf("failed to put debug version state into disk, err: %s", err.Error()))
}
}
func (hs *DebugHashState) sortItems() {
sort.Slice(hs.GetAccounts, func(i, j int) bool {
return hs.GetAccounts[i].Address.Cmp(hs.GetAccounts[j].Address) < 0
})
sort.Slice(hs.UpdateAccounts, func(i, j int) bool {
return hs.UpdateAccounts[i].Address.Cmp(hs.UpdateAccounts[j].Address) < 0
})
sort.Slice(hs.DeleteAccounts, func(i, j int) bool {
return hs.DeleteAccounts[i].Cmp(hs.DeleteAccounts[j]) < 0
})
sort.Slice(hs.GetStorage, func(i, j int) bool {
if hs.GetStorage[i].Address.Cmp(hs.GetStorage[j].Address) == 0 {
return hs.GetStorage[i].Key < hs.GetStorage[j].Key
}
return hs.GetStorage[i].Address.Cmp(hs.GetStorage[j].Address) < 0
})
sort.Slice(hs.UpdateStorage, func(i, j int) bool {
if hs.UpdateStorage[i].Address.Cmp(hs.UpdateStorage[j].Address) == 0 {
return hs.UpdateStorage[i].Key < hs.UpdateStorage[j].Key
}
return hs.UpdateStorage[i].Address.Cmp(hs.UpdateStorage[j].Address) < 0
})
sort.Slice(hs.DeleteStorage, func(i, j int) bool {
if hs.DeleteStorage[i].Address.Cmp(hs.DeleteStorage[j].Address) == 0 {
return hs.DeleteStorage[i].Key < hs.DeleteStorage[j].Key
}
return hs.DeleteStorage[i].Address.Cmp(hs.DeleteStorage[j].Address) < 0
})
}
func DebugHashStateKey(version int64) []byte {
key := "debug_hash_prefix" + strconv.FormatInt(version, 10)
return []byte(key)
}

View File

@@ -0,0 +1,290 @@
package state
import (
"encoding/json"
"fmt"
"sort"
"strconv"
"sync"
versa "github.com/bnb-chain/versioned-state-database"
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/core/types"
"github.com/ethereum/go-ethereum/ethdb"
"github.com/ethereum/go-ethereum/log"
)
var (
DiffVersionCount = 0
DiskVersionCount = 0
)
type VersaAccountInfo struct {
Address common.Address
Account *types.StateAccount
}
type VersaStorageInfo struct {
Handler versa.TreeHandler
Address common.Address
Key string
Val string
}
type DebugVersionState struct {
disk ethdb.KeyValueStore
versionDB versa.Database
lock sync.Mutex
Version int64
PreState *versa.StateInfo
PostState *versa.StateInfo
AccessTrees map[common.Address][]*versa.TreeInfo
CommitTrees map[common.Address][]*versa.TreeInfo
CalcHash map[common.Address]common.Hash
GetAccounts []*VersaAccountInfo
UpdateAccounts []*VersaAccountInfo
DeleteAccounts []common.Address
GetStorage []*VersaStorageInfo
UpdateStorage []*VersaStorageInfo
DeleteStorage []*VersaStorageInfo
StorageAddr2Owner map[common.Address]common.Hash
GetCode map[common.Address][]common.Hash
UpdateCode map[common.Address][]common.Hash
Errs []string
}
func NewDebugVersionState(disk ethdb.KeyValueStore, versionDB versa.Database) *DebugVersionState {
return &DebugVersionState{
disk: disk,
versionDB: versionDB,
AccessTrees: make(map[common.Address][]*versa.TreeInfo, 0),
CommitTrees: make(map[common.Address][]*versa.TreeInfo, 0),
CalcHash: make(map[common.Address]common.Hash),
GetAccounts: make([]*VersaAccountInfo, 0),
UpdateAccounts: make([]*VersaAccountInfo, 0),
DeleteAccounts: make([]common.Address, 0),
GetStorage: make([]*VersaStorageInfo, 0),
UpdateStorage: make([]*VersaStorageInfo, 0),
DeleteStorage: make([]*VersaStorageInfo, 0),
StorageAddr2Owner: make(map[common.Address]common.Hash),
GetCode: make(map[common.Address][]common.Hash, 0),
UpdateCode: make(map[common.Address][]common.Hash, 0),
Errs: make([]string, 0),
}
}
func (ds *DebugVersionState) SetVersion(version int64) {
ds.lock.Lock()
defer ds.lock.Unlock()
ds.Version = version
}
func (ds *DebugVersionState) OnOpenState(handler versa.StateHandler) {
ds.lock.Lock()
defer ds.lock.Unlock()
stateInfo, err := ds.versionDB.GetStateInfo(handler)
if err != nil {
panic(fmt.Sprintf("failed to get state info on open state, err: %s", err.Error()))
}
ds.PreState = stateInfo
}
func (ds *DebugVersionState) OnOpenTree(handler versa.TreeHandler, owner common.Hash, address common.Address) {
ds.lock.Lock()
defer ds.lock.Unlock()
treeInfo, err := ds.versionDB.GetTreeInfo(handler)
if err != nil {
panic(fmt.Sprintf("failed to get tree info on open tree, err: %s", err.Error()))
}
if _, ok := ds.AccessTrees[address]; !ok {
ds.AccessTrees[address] = make([]*versa.TreeInfo, 0)
}
ds.AccessTrees[address] = append(ds.AccessTrees[address], treeInfo)
ds.StorageAddr2Owner[address] = owner
}
func (ds *DebugVersionState) OnGetAccount(addr common.Address, acc *types.StateAccount) {
ds.lock.Lock()
defer ds.lock.Unlock()
ds.GetAccounts = append(ds.GetAccounts, &VersaAccountInfo{
Address: addr,
Account: acc,
})
}
func (ds *DebugVersionState) OnUpdateAccount(addr common.Address, acc *types.StateAccount) {
ds.lock.Lock()
defer ds.lock.Unlock()
ds.UpdateAccounts = append(ds.UpdateAccounts, &VersaAccountInfo{
Address: addr,
Account: acc,
})
}
func (ds *DebugVersionState) OnDeleteAccount(address common.Address) {
ds.lock.Lock()
defer ds.lock.Unlock()
ds.DeleteAccounts = append(ds.DeleteAccounts, address)
}
func (ds *DebugVersionState) OnGetStorage(handler versa.TreeHandler, address common.Address, key []byte, val []byte) {
ds.lock.Lock()
defer ds.lock.Unlock()
ds.GetStorage = append(ds.GetStorage, &VersaStorageInfo{
Handler: handler,
Address: address,
Key: common.Bytes2Hex(key),
Val: common.Bytes2Hex(val),
})
}
func (ds *DebugVersionState) OnUpdateStorage(handler versa.TreeHandler, address common.Address, key []byte, val []byte) {
ds.lock.Lock()
defer ds.lock.Unlock()
ds.UpdateStorage = append(ds.UpdateStorage, &VersaStorageInfo{
Handler: handler,
Address: address,
Key: common.Bytes2Hex(key),
Val: common.Bytes2Hex(val),
})
}
func (ds *DebugVersionState) OnDeleteStorage(handler versa.TreeHandler, address common.Address, key []byte) {
ds.lock.Lock()
defer ds.lock.Unlock()
ds.DeleteStorage = append(ds.DeleteStorage, &VersaStorageInfo{
Handler: handler,
Address: address,
Key: common.Bytes2Hex(key),
})
}
func (ds *DebugVersionState) OnGetCode(addr common.Address, codeHash common.Hash) {
ds.lock.Lock()
defer ds.lock.Unlock()
if _, ok := ds.GetCode[addr]; !ok {
ds.GetCode[addr] = make([]common.Hash, 0)
}
ds.GetCode[addr] = append(ds.GetCode[addr], codeHash)
}
func (ds *DebugVersionState) OnUpdateCode(addr common.Address, codeHash common.Hash) {
ds.lock.Lock()
defer ds.lock.Unlock()
if _, ok := ds.UpdateCode[addr]; !ok {
ds.UpdateCode[addr] = make([]common.Hash, 0)
}
ds.UpdateCode[addr] = append(ds.UpdateCode[addr], codeHash)
}
func (ds *DebugVersionState) OnCalcHash(addr common.Address, root common.Hash) {
ds.lock.Lock()
defer ds.lock.Unlock()
ds.CalcHash[addr] = root
}
func (ds *DebugVersionState) OnCommitTree(addr common.Address, handler versa.TreeHandler) {
ds.lock.Lock()
defer ds.lock.Unlock()
treeInfo, err := ds.versionDB.GetTreeInfo(handler)
if err != nil {
panic(fmt.Sprintf("failed to get tree info on commit tree, err: %s", err.Error()))
}
if _, ok := ds.CommitTrees[addr]; !ok {
ds.CommitTrees[addr] = make([]*versa.TreeInfo, 0)
}
ds.CommitTrees[addr] = append(ds.CommitTrees[addr], treeInfo)
}
func (ds *DebugVersionState) OnError(err error) {
ds.lock.Lock()
defer ds.lock.Unlock()
ds.Errs = append(ds.Errs, err.Error())
}
func (ds *DebugVersionState) OnCloseState(handler versa.StateHandler) {
ds.lock.Lock()
defer ds.lock.Unlock()
stateInfo, err := ds.versionDB.GetStateInfo(handler)
if err != nil {
panic(fmt.Sprintf("failed to get state info on close state, err: %s", err.Error()))
}
ds.PostState = stateInfo
oldDiskVersionCount := DiskVersionCount
if ds.PreState.Root.Cmp(ds.PostState.Root) != 0 {
DiffVersionCount++
if ds.PostState.IsDiskVersion {
DiskVersionCount++
}
}
if ds.Version%1000 == 0 || oldDiskVersionCount != DiskVersionCount {
log.Info("version state info", "current block", ds.Version, "diff version count", DiffVersionCount, "disk version count", DiskVersionCount)
}
ds.sortItems()
data, err := json.Marshal(ds)
if err != nil {
panic(fmt.Sprintf("failed to json encode debug info, err: %s", err.Error()))
}
err = ds.disk.Put(DebugVersionStateKey(ds.Version), data)
if err != nil {
panic(fmt.Sprintf("failed to put debug version state into disk, err: %s", err.Error()))
}
if len(ds.Errs) != 0 {
log.Info("version state occurs error", "debug info", string(data))
log.Crit("exit....")
}
}
func (ds *DebugVersionState) sortItems() {
sort.Slice(ds.GetAccounts, func(i, j int) bool {
return ds.GetAccounts[i].Address.Cmp(ds.GetAccounts[j].Address) < 0
})
sort.Slice(ds.UpdateAccounts, func(i, j int) bool {
return ds.UpdateAccounts[i].Address.Cmp(ds.UpdateAccounts[j].Address) < 0
})
sort.Slice(ds.DeleteAccounts, func(i, j int) bool {
return ds.DeleteAccounts[i].Cmp(ds.DeleteAccounts[j]) < 0
})
sort.Slice(ds.GetStorage, func(i, j int) bool {
if ds.GetStorage[i].Address.Cmp(ds.GetStorage[j].Address) == 0 {
return ds.GetStorage[i].Key < ds.GetStorage[j].Key
}
return ds.GetStorage[i].Address.Cmp(ds.GetStorage[j].Address) < 0
})
sort.Slice(ds.UpdateStorage, func(i, j int) bool {
if ds.UpdateStorage[i].Address.Cmp(ds.UpdateStorage[j].Address) == 0 {
return ds.UpdateStorage[i].Key < ds.UpdateStorage[j].Key
}
return ds.UpdateStorage[i].Address.Cmp(ds.UpdateStorage[j].Address) < 0
})
sort.Slice(ds.DeleteStorage, func(i, j int) bool {
if ds.DeleteStorage[i].Address.Cmp(ds.DeleteStorage[j].Address) == 0 {
return ds.DeleteStorage[i].Key < ds.DeleteStorage[j].Key
}
return ds.DeleteStorage[i].Address.Cmp(ds.DeleteStorage[j].Address) < 0
})
}
func DebugVersionStateKey(version int64) []byte {
key := "debug_version_prefix" + strconv.FormatInt(version, 10)
return []byte(key)
}

View File

@@ -81,6 +81,7 @@ type triePrefetcher struct {
// newTriePrefetcher
func newTriePrefetcher(db Database, root, rootParent common.Hash, namespace string) *triePrefetcher {
panic("prefetcher not support")
prefix := triePrefetchMetricsPrefix + namespace
p := &triePrefetcher{
db: db,

View File

@@ -49,6 +49,7 @@ func NewStatePrefetcher(config *params.ChainConfig, bc *BlockChain, engine conse
// the transaction messages using the statedb, but any changes are discarded. The
// only goal is to pre-cache transaction signatures and state trie nodes.
func (p *statePrefetcher) Prefetch(block *types.Block, statedb *state.StateDB, cfg *vm.Config, interruptCh <-chan struct{}) {
panic("prefetcher not support")
var (
header = block.Header()
signer = types.MakeSigner(p.config, header.Number, header.Time)
@@ -101,6 +102,7 @@ func (p *statePrefetcher) Prefetch(block *types.Block, statedb *state.StateDB, c
// the transaction messages using the statedb, but any changes are discarded. The
// only goal is to pre-cache transaction signatures and snapshot clean state. Only used for mining stage
func (p *statePrefetcher) PrefetchMining(txs TransactionsByPriceAndNonce, header *types.Header, gasLimit uint64, statedb *state.StateDB, cfg vm.Config, interruptCh <-chan struct{}, txCurr **types.Transaction) {
panic("prefetcher not support")
var signer = types.MakeSigner(p.config, header.Number, header.Time)
txCh := make(chan *types.Transaction, 2*prefetchThread)

View File

@@ -231,13 +231,6 @@ func ApplyTransaction(config *params.ChainConfig, bc ChainContext, author *commo
// ProcessBeaconBlockRoot applies the EIP-4788 system call to the beacon block root
// contract. This method is exported to be used in tests.
func ProcessBeaconBlockRoot(beaconRoot common.Hash, vmenv *vm.EVM, statedb *state.StateDB) {
// Return immediately if beaconRoot equals the zero hash when using the Parlia engine.
if beaconRoot == (common.Hash{}) {
if chainConfig := vmenv.ChainConfig(); chainConfig != nil && chainConfig.Parlia != nil {
return
}
}
// If EIP-4788 is enabled, we need to invoke the beaconroot storage contract with
// the new root
msg := &Message{

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@@ -1,27 +0,0 @@
package bohr
import _ "embed"
// contract codes for Mainnet upgrade
var (
//go:embed mainnet/ValidatorContract
MainnetValidatorContract string
//go:embed mainnet/StakeHubContract
MainnetStakeHubContract string
)
// contract codes for Chapel upgrade
var (
//go:embed chapel/ValidatorContract
ChapelValidatorContract string
//go:embed chapel/StakeHubContract
ChapelStakeHubContract string
)
// contract codes for Rialto upgrade
var (
//go:embed rialto/ValidatorContract
RialtoValidatorContract string
//go:embed rialto/StakeHubContract
RialtoStakeHubContract string
)

View File

@@ -4,11 +4,10 @@ import (
"encoding/hex"
"fmt"
"math/big"
"reflect"
"strings"
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/core/systemcontracts/bohr"
"github.com/ethereum/go-ethereum/core/state"
"github.com/ethereum/go-ethereum/core/systemcontracts/bruno"
"github.com/ethereum/go-ethereum/core/systemcontracts/euler"
"github.com/ethereum/go-ethereum/core/systemcontracts/feynman"
@@ -23,7 +22,6 @@ 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"
)
@@ -41,7 +39,7 @@ type Upgrade struct {
Configs []*UpgradeConfig
}
type upgradeHook func(blockNumber *big.Int, contractAddr common.Address, statedb vm.StateDB) error
type upgradeHook func(blockNumber *big.Int, contractAddr common.Address, statedb *state.StateDB) error
const (
mainNet = "Mainnet"
@@ -80,8 +78,6 @@ var (
feynmanFixUpgrade = make(map[string]*Upgrade)
haberFixUpgrade = make(map[string]*Upgrade)
bohrUpgrade = make(map[string]*Upgrade)
)
func init() {
@@ -740,61 +736,12 @@ func init() {
},
},
}
bohrUpgrade[mainNet] = &Upgrade{
UpgradeName: "bohr",
Configs: []*UpgradeConfig{
{
ContractAddr: common.HexToAddress(ValidatorContract),
CommitUrl: "https://github.com/bnb-chain/bsc-genesis-contract/commit/398c9364aad5261c1ecd90ac3ab2df89b65c45e3",
Code: bohr.MainnetValidatorContract,
},
{
ContractAddr: common.HexToAddress(StakeHubContract),
CommitUrl: "https://github.com/bnb-chain/bsc-genesis-contract/commit/398c9364aad5261c1ecd90ac3ab2df89b65c45e3",
Code: bohr.MainnetStakeHubContract,
},
},
}
bohrUpgrade[chapelNet] = &Upgrade{
UpgradeName: "bohr",
Configs: []*UpgradeConfig{
{
ContractAddr: common.HexToAddress(ValidatorContract),
CommitUrl: "https://github.com/bnb-chain/bsc-genesis-contract/commit/398c9364aad5261c1ecd90ac3ab2df89b65c45e3",
Code: bohr.ChapelValidatorContract,
},
{
ContractAddr: common.HexToAddress(StakeHubContract),
CommitUrl: "https://github.com/bnb-chain/bsc-genesis-contract/commit/398c9364aad5261c1ecd90ac3ab2df89b65c45e3",
Code: bohr.ChapelStakeHubContract,
},
},
}
bohrUpgrade[rialtoNet] = &Upgrade{
UpgradeName: "bohr",
Configs: []*UpgradeConfig{
{
ContractAddr: common.HexToAddress(ValidatorContract),
CommitUrl: "https://github.com/bnb-chain/bsc-genesis-contract/commit/398c9364aad5261c1ecd90ac3ab2df89b65c45e3",
Code: bohr.RialtoValidatorContract,
},
{
ContractAddr: common.HexToAddress(StakeHubContract),
CommitUrl: "https://github.com/bnb-chain/bsc-genesis-contract/commit/398c9364aad5261c1ecd90ac3ab2df89b65c45e3",
Code: bohr.RialtoStakeHubContract,
},
},
}
}
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() {
func UpgradeBuildInSystemContract(config *params.ChainConfig, blockNumber *big.Int, lastBlockTime uint64, blockTime uint64, statedb *state.StateDB) {
if config == nil || blockNumber == nil || statedb == nil {
return
}
var network string
switch GenesisHash {
/* Add mainnet genesis hash */
@@ -869,16 +816,12 @@ func UpgradeBuildInSystemContract(config *params.ChainConfig, blockNumber *big.I
applySystemContractUpgrade(haberFixUpgrade[network], blockNumber, statedb, logger)
}
if config.IsOnBohr(blockNumber, lastBlockTime, blockTime) {
applySystemContractUpgrade(bohrUpgrade[network], blockNumber, statedb, logger)
}
/*
apply other upgrades
*/
}
func applySystemContractUpgrade(upgrade *Upgrade, blockNumber *big.Int, statedb vm.StateDB, logger log.Logger) {
func applySystemContractUpgrade(upgrade *Upgrade, blockNumber *big.Int, statedb *state.StateDB, logger log.Logger) {
if upgrade == nil {
logger.Info("Empty upgrade config", "height", blockNumber.String())
return

View File

@@ -2,13 +2,9 @@ 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"
)
@@ -43,31 +39,3 @@ 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)
}

View File

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

View File

@@ -673,7 +673,10 @@ type DiffAccountsInBlock struct {
Transactions []DiffAccountsInTx
}
var extraSeal = 65 // Fixed number of extra-data suffix bytes reserved for signer seal
var (
extraVanity = 32 // Fixed number of extra-data prefix bytes reserved for signer vanity
extraSeal = 65 // Fixed number of extra-data suffix bytes reserved for signer seal
)
// SealHash returns the hash of a block prior to it being sealed.
func SealHash(header *Header, chainId *big.Int) (hash common.Hash) {
@@ -684,33 +687,7 @@ func SealHash(header *Header, chainId *big.Int) (hash common.Hash) {
}
func EncodeSigHeader(w io.Writer, header *Header, chainId *big.Int) {
var err error
if header.ParentBeaconRoot != nil && *header.ParentBeaconRoot == (common.Hash{}) {
err = rlp.Encode(w, []interface{}{
chainId,
header.ParentHash,
header.UncleHash,
header.Coinbase,
header.Root,
header.TxHash,
header.ReceiptHash,
header.Bloom,
header.Difficulty,
header.Number,
header.GasLimit,
header.GasUsed,
header.Time,
header.Extra[:len(header.Extra)-extraSeal], // this will panic if extra is too short, should check before calling encodeSigHeader
header.MixDigest,
header.Nonce,
header.BaseFee,
header.WithdrawalsHash,
header.BlobGasUsed,
header.ExcessBlobGas,
header.ParentBeaconRoot,
})
} else {
err = rlp.Encode(w, []interface{}{
err := rlp.Encode(w, []interface{}{
chainId,
header.ParentHash,
header.UncleHash,
@@ -728,7 +705,30 @@ func EncodeSigHeader(w io.Writer, header *Header, chainId *big.Int) {
header.MixDigest,
header.Nonce,
})
}
if err != nil {
panic("can't encode: " + err.Error())
}
}
func EncodeSigHeaderWithoutVoteAttestation(w io.Writer, header *Header, chainId *big.Int) {
err := rlp.Encode(w, []interface{}{
chainId,
header.ParentHash,
header.UncleHash,
header.Coinbase,
header.Root,
header.TxHash,
header.ReceiptHash,
header.Bloom,
header.Difficulty,
header.Number,
header.GasLimit,
header.GasUsed,
header.Time,
header.Extra[:extraVanity], // this will panic if extra is too short, should check before calling encodeSigHeaderWithoutVoteAttestation
header.MixDigest,
header.Nonce,
})
if err != nil {
panic("can't encode: " + err.Error())
}

View File

@@ -18,6 +18,7 @@ package types
import (
"bytes"
"fmt"
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/rlp"
@@ -58,6 +59,11 @@ func (acct *StateAccount) Copy() *StateAccount {
}
}
func (acct *StateAccount) String() string {
return fmt.Sprintf("nonce: %d, balance: %d, root: %s, codeHash: %s",
acct.Nonce, acct.Balance, acct.Root.String(), common.Bytes2Hex(acct.CodeHash))
}
// SlimAccount is a modified version of an Account, where the root is replaced
// with a byte slice. This format can be used to represent full-consensus format
// or slim format which replaces the empty root and code hash as nil byte slice.

View File

@@ -3,7 +3,6 @@ package vote
import (
"bytes"
"fmt"
"math/big"
"sync"
"time"
@@ -20,13 +19,7 @@ import (
const blocksNumberSinceMining = 5 // the number of blocks need to wait before voting, counting from the validator begin to mine
var diffInTurn = big.NewInt(2) // Block difficulty for in-turn signatures
var votesManagerCounter = metrics.NewRegisteredCounter("votesManager/local", nil)
var notJustified = metrics.NewRegisteredCounter("votesManager/notJustified", nil)
var inTurnJustified = metrics.NewRegisteredCounter("votesManager/inTurnJustified", nil)
var notInTurnJustified = metrics.NewRegisteredCounter("votesManager/notInTurnJustified", nil)
var continuousJustified = metrics.NewRegisteredCounter("votesManager/continuousJustified", nil)
var notContinuousJustified = metrics.NewRegisteredCounter("votesManager/notContinuousJustified", nil)
// Backend wraps all methods required for voting.
type Backend interface {
@@ -40,8 +33,8 @@ type VoteManager struct {
chain *core.BlockChain
highestVerifiedBlockCh chan core.HighestVerifiedBlockEvent
highestVerifiedBlockSub event.Subscription
chainHeadCh chan core.ChainHeadEvent
chainHeadSub event.Subscription
// used for backup validators to sync votes from corresponding mining validator
syncVoteCh chan core.NewVoteEvent
@@ -58,7 +51,7 @@ func NewVoteManager(eth Backend, chain *core.BlockChain, pool *VotePool, journal
voteManager := &VoteManager{
eth: eth,
chain: chain,
highestVerifiedBlockCh: make(chan core.HighestVerifiedBlockEvent, highestVerifiedBlockChanSize),
chainHeadCh: make(chan core.ChainHeadEvent, chainHeadChanSize),
syncVoteCh: make(chan core.NewVoteEvent, voteBufferForPut),
pool: pool,
engine: engine,
@@ -81,7 +74,7 @@ func NewVoteManager(eth Backend, chain *core.BlockChain, pool *VotePool, journal
voteManager.journal = voteJournal
// Subscribe to chain head event.
voteManager.highestVerifiedBlockSub = voteManager.chain.SubscribeHighestVerifiedHeaderEvent(voteManager.highestVerifiedBlockCh)
voteManager.chainHeadSub = voteManager.chain.SubscribeChainHeadEvent(voteManager.chainHeadCh)
voteManager.syncVoteSub = voteManager.pool.SubscribeNewVoteEvent(voteManager.syncVoteCh)
go voteManager.loop()
@@ -91,7 +84,7 @@ func NewVoteManager(eth Backend, chain *core.BlockChain, pool *VotePool, journal
func (voteManager *VoteManager) loop() {
log.Debug("vote manager routine loop started")
defer voteManager.highestVerifiedBlockSub.Unsubscribe()
defer voteManager.chainHeadSub.Unsubscribe()
defer voteManager.syncVoteSub.Unsubscribe()
events := voteManager.eth.EventMux().Subscribe(downloader.StartEvent{}, downloader.DoneEvent{}, downloader.FailedEvent{})
@@ -126,7 +119,7 @@ func (voteManager *VoteManager) loop() {
log.Debug("downloader is in DoneEvent mode, set the startVote flag to true")
startVote = true
}
case cHead := <-voteManager.highestVerifiedBlockCh:
case cHead := <-voteManager.chainHeadCh:
if !startVote {
log.Debug("startVote flag is false, continue")
continue
@@ -142,12 +135,12 @@ func (voteManager *VoteManager) loop() {
continue
}
if cHead.Header == nil {
log.Debug("cHead.Header is nil, continue")
if cHead.Block == nil {
log.Debug("cHead.Block is nil, continue")
continue
}
curHead := cHead.Header
curHead := cHead.Block.Header()
if p, ok := voteManager.engine.(*parlia.Parlia); ok {
nextBlockMinedTime := time.Unix(int64((curHead.Time + p.Period())), 0)
timeForBroadcast := 50 * time.Millisecond // enough to broadcast a vote
@@ -162,7 +155,7 @@ func (voteManager *VoteManager) loop() {
func(bLSPublicKey *types.BLSPublicKey) bool {
return bytes.Equal(voteManager.signer.PubKey[:], bLSPublicKey[:])
}) {
log.Debug("local validator with voteKey is not within the validatorSet at curHead")
log.Debug("cur validator is not within the validatorSet at curHead")
continue
}
@@ -209,36 +202,6 @@ func (voteManager *VoteManager) loop() {
voteManager.pool.PutVote(voteMessage)
votesManagerCounter.Inc(1)
}
// check the latest justified block, which indicating the stability of the network
curJustifiedNumber, _, err := voteManager.engine.GetJustifiedNumberAndHash(voteManager.chain, []*types.Header{curHead})
if err == nil && curJustifiedNumber != 0 {
if curJustifiedNumber+1 != curHead.Number.Uint64() {
log.Debug("not justified", "blockNumber", curHead.Number.Uint64()-1)
notJustified.Inc(1)
} else {
parent := voteManager.chain.GetHeaderByHash(curHead.ParentHash)
if parent != nil {
if parent.Difficulty.Cmp(diffInTurn) == 0 {
inTurnJustified.Inc(1)
} else {
log.Debug("not in turn block justified", "blockNumber", parent.Number.Int64(), "blockHash", parent.Hash())
notInTurnJustified.Inc(1)
}
lastJustifiedNumber, _, err := voteManager.engine.GetJustifiedNumberAndHash(voteManager.chain, []*types.Header{parent})
if err == nil {
if lastJustifiedNumber == 0 || lastJustifiedNumber+1 == curJustifiedNumber {
continuousJustified.Inc(1)
} else {
log.Debug("not continuous block justified", "lastJustified", lastJustifiedNumber, "curJustified", curJustifiedNumber)
notContinuousJustified.Inc(1)
}
}
}
}
}
case event := <-voteManager.syncVoteCh:
voteMessage := event.Vote
if voteManager.eth.IsMining() || !bytes.Equal(voteManager.signer.PubKey[:], voteMessage.VoteAddress[:]) {
@@ -254,7 +217,7 @@ func (voteManager *VoteManager) loop() {
case <-voteManager.syncVoteSub.Err():
log.Debug("voteManager subscribed votes failed")
return
case <-voteManager.highestVerifiedBlockSub.Err():
case <-voteManager.chainHeadSub.Err():
log.Debug("voteManager subscribed chainHead failed")
return
}

View File

@@ -24,7 +24,7 @@ const (
lowerLimitOfVoteBlockNumber = 256
upperLimitOfVoteBlockNumber = 11 // refer to fetcher.maxUncleDist
highestVerifiedBlockChanSize = 10 // highestVerifiedBlockChanSize is the size of channel listening to HighestVerifiedBlockEvent.
chainHeadChanSize = 10 // chainHeadChanSize is the size of channel listening to ChainHeadEvent.
)
var (
@@ -57,8 +57,8 @@ type VotePool struct {
curVotesPq *votesPriorityQueue
futureVotesPq *votesPriorityQueue
highestVerifiedBlockCh chan core.HighestVerifiedBlockEvent
highestVerifiedBlockSub event.Subscription
chainHeadCh chan core.ChainHeadEvent
chainHeadSub event.Subscription
votesCh chan *types.VoteEnvelope
@@ -75,13 +75,13 @@ func NewVotePool(chain *core.BlockChain, engine consensus.PoSA) *VotePool {
futureVotes: make(map[common.Hash]*VoteBox),
curVotesPq: &votesPriorityQueue{},
futureVotesPq: &votesPriorityQueue{},
highestVerifiedBlockCh: make(chan core.HighestVerifiedBlockEvent, highestVerifiedBlockChanSize),
chainHeadCh: make(chan core.ChainHeadEvent, chainHeadChanSize),
votesCh: make(chan *types.VoteEnvelope, voteBufferForPut),
engine: engine,
}
// Subscribe events from blockchain and start the main event loop.
votePool.highestVerifiedBlockSub = votePool.chain.SubscribeHighestVerifiedHeaderEvent(votePool.highestVerifiedBlockCh)
votePool.chainHeadSub = votePool.chain.SubscribeChainHeadEvent(votePool.chainHeadCh)
go votePool.loop()
return votePool
@@ -89,18 +89,18 @@ func NewVotePool(chain *core.BlockChain, engine consensus.PoSA) *VotePool {
// loop is the vote pool's main even loop, waiting for and reacting to outside blockchain events and votes channel event.
func (pool *VotePool) loop() {
defer pool.highestVerifiedBlockSub.Unsubscribe()
defer pool.chainHeadSub.Unsubscribe()
for {
select {
// Handle ChainHeadEvent.
case ev := <-pool.highestVerifiedBlockCh:
if ev.Header != nil {
latestBlockNumber := ev.Header.Number.Uint64()
case ev := <-pool.chainHeadCh:
if ev.Block != nil {
latestBlockNumber := ev.Block.NumberU64()
pool.prune(latestBlockNumber)
pool.transferVotesFromFutureToCur(ev.Header)
pool.transferVotesFromFutureToCur(ev.Block.Header())
}
case <-pool.highestVerifiedBlockSub.Err():
case <-pool.chainHeadSub.Err():
return
// Handle votes channel and put the vote into vote pool.
@@ -135,7 +135,7 @@ func (pool *VotePool) putIntoVotePool(vote *types.VoteEnvelope) bool {
var votesPq *votesPriorityQueue
isFutureVote := false
voteBlock := pool.chain.GetVerifiedBlockByHash(targetHash)
voteBlock := pool.chain.GetHeaderByHash(targetHash)
if voteBlock == nil {
votes = pool.futureVotes
votesPq = pool.futureVotesPq
@@ -226,7 +226,7 @@ func (pool *VotePool) transferVotesFromFutureToCur(latestBlockHeader *types.Head
futurePqBuffer := make([]*types.VoteData, 0)
for futurePq.Len() > 0 && futurePq.Peek().TargetNumber <= latestBlockNumber {
blockHash := futurePq.Peek().TargetHash
header := pool.chain.GetVerifiedBlockByHash(blockHash)
header := pool.chain.GetHeaderByHash(blockHash)
if header == nil {
// Put into pq buffer used for later put again into futurePq
futurePqBuffer = append(futurePqBuffer, heap.Pop(futurePq).(*types.VoteData))

View File

@@ -26,7 +26,6 @@ import (
"github.com/ethereum/go-ethereum/accounts"
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/consensus"
"github.com/ethereum/go-ethereum/consensus/parlia"
"github.com/ethereum/go-ethereum/core"
"github.com/ethereum/go-ethereum/core/bloombits"
"github.com/ethereum/go-ethereum/core/rawdb"
@@ -441,16 +440,6 @@ func (b *EthAPIBackend) Engine() consensus.Engine {
return b.eth.engine
}
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).GetValidators(&currentHead)
}
return []common.Address{}, errors.New("not supported")
}
func (b *EthAPIBackend) CurrentHeader() *types.Header {
return b.eth.blockchain.CurrentHeader()
}

View File

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

View File

@@ -123,6 +123,18 @@ type Ethereum struct {
// New creates a new Ethereum object (including the
// initialisation of the common Ethereum object)
func New(stack *node.Node, config *ethconfig.Config) (*Ethereum, error) {
onlyFullSync := false
if config.StateScheme == rawdb.VersionScheme {
config.SnapshotCache = 0
onlyFullSync = true
config.SyncMode = downloader.FullSync
}
// TODO:: debug code
config.SnapshotCache = 0
onlyFullSync = true
config.SyncMode = downloader.FullSync
// Ensure configuration values are compatible and sane
if config.SyncMode == downloader.LightSync {
return nil, errors.New("can't run eth.Ethereum in light sync mode, light mode has been deprecated")
@@ -185,16 +197,6 @@ func New(stack *node.Node, config *ethconfig.Config) (*Ethereum, error) {
}
// Override the chain config with provided settings.
var overrides core.ChainOverrides
if config.OverridePassedForkTime != nil {
chainConfig.ShanghaiTime = config.OverridePassedForkTime
chainConfig.KeplerTime = config.OverridePassedForkTime
chainConfig.FeynmanTime = config.OverridePassedForkTime
chainConfig.FeynmanFixTime = config.OverridePassedForkTime
chainConfig.CancunTime = config.OverridePassedForkTime
chainConfig.HaberTime = config.OverridePassedForkTime
chainConfig.HaberFixTime = config.OverridePassedForkTime
overrides.OverridePassedForkTime = config.OverridePassedForkTime
}
if config.OverrideBohr != nil {
chainConfig.BohrTime = config.OverrideBohr
overrides.OverrideBohr = config.OverrideBohr
@@ -338,6 +340,7 @@ func New(stack *node.Node, config *ethconfig.Config) (*Ethereum, error) {
DirectBroadcast: config.DirectBroadcast,
DisablePeerTxBroadcast: config.DisablePeerTxBroadcast,
PeerSet: peers,
OnlyFullSync: onlyFullSync,
}); err != nil {
return nil, err
}

View File

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

View File

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

View File

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

View File

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

View File

@@ -188,9 +188,6 @@ type Config struct {
// send-transaction variants. The unit is ether.
RPCTxFeeCap float64
// OverridePassedForkTime
OverridePassedForkTime *uint64 `toml:",omitempty"`
// OverrideBohr (TODO: remove after the fork)
OverrideBohr *uint64 `toml:",omitempty"`

View File

@@ -70,7 +70,6 @@ func (c Config) MarshalTOML() (interface{}, error) {
RPCGasCap uint64
RPCEVMTimeout time.Duration
RPCTxFeeCap float64
OverridePassedForkTime *uint64 `toml:",omitempty"`
OverrideBohr *uint64 `toml:",omitempty"`
OverrideVerkle *uint64 `toml:",omitempty"`
BlobExtraReserve uint64
@@ -129,7 +128,6 @@ func (c Config) MarshalTOML() (interface{}, error) {
enc.RPCGasCap = c.RPCGasCap
enc.RPCEVMTimeout = c.RPCEVMTimeout
enc.RPCTxFeeCap = c.RPCTxFeeCap
enc.OverridePassedForkTime = c.OverridePassedForkTime
enc.OverrideBohr = c.OverrideBohr
enc.OverrideVerkle = c.OverrideVerkle
enc.BlobExtraReserve = c.BlobExtraReserve
@@ -192,7 +190,6 @@ func (c *Config) UnmarshalTOML(unmarshal func(interface{}) error) error {
RPCGasCap *uint64
RPCEVMTimeout *time.Duration
RPCTxFeeCap *float64
OverridePassedForkTime *uint64 `toml:",omitempty"`
OverrideBohr *uint64 `toml:",omitempty"`
OverrideVerkle *uint64 `toml:",omitempty"`
BlobExtraReserve *uint64
@@ -360,9 +357,6 @@ func (c *Config) UnmarshalTOML(unmarshal func(interface{}) error) error {
if dec.RPCTxFeeCap != nil {
c.RPCTxFeeCap = *dec.RPCTxFeeCap
}
if dec.OverridePassedForkTime != nil {
c.OverridePassedForkTime = dec.OverridePassedForkTime
}
if dec.OverrideBohr != nil {
c.OverrideBohr = dec.OverrideBohr
}

View File

@@ -436,7 +436,7 @@ func TestInvalidLogFilterCreation(t *testing.T) {
}
}
// TestInvalidGetLogsRequest tests invalid getLogs requests
// TestLogFilterUninstall tests invalid getLogs requests
func TestInvalidGetLogsRequest(t *testing.T) {
t.Parallel()

View File

@@ -124,6 +124,7 @@ type handlerConfig struct {
DirectBroadcast bool
DisablePeerTxBroadcast bool
PeerSet *peerSet
OnlyFullSync bool
}
type handler struct {
@@ -172,8 +173,6 @@ type handler struct {
handlerStartCh chan struct{}
handlerDoneCh chan struct{}
blackList *blackList
}
// newHandler returns a handler for all Ethereum chain management protocol.
@@ -204,6 +203,7 @@ func newHandler(config *handlerConfig) (*handler, error) {
handlerStartCh: make(chan struct{}),
stopCh: make(chan struct{}),
}
if !config.OnlyFullSync {
if config.Sync == downloader.FullSync {
// The database seems empty as the current block is the genesis. Yet the snap
// block is ahead, so snap sync was enabled for this node at a certain point.
@@ -235,6 +235,7 @@ func newHandler(config *handlerConfig) (*handler, error) {
log.Info("Enabled snap sync", "head", head.Number, "hash", head.Hash())
}
}
}
// If snap sync is requested but snapshots are disabled, fail loudly
if h.snapSync.Load() && config.Chain.Snapshots() == nil {
return nil, errors.New("snap sync not supported with snapshots disabled")
@@ -485,13 +486,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())
@@ -634,7 +635,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, "name", peer.Name())
peer.Log().Error("Bsc extension registration failed", "err", err)
return err
}
return handler(peer)
@@ -704,7 +705,6 @@ func (h *handler) unregisterPeer(id string) {
func (h *handler) Start(maxPeers int, maxPeersPerIP int) {
h.maxPeers = maxPeers
h.maxPeersPerIP = maxPeersPerIP
h.blackList = NewBlackList(maxPeers, 1*time.Hour, 3)
// broadcast and announce transactions (only new ones, not resurrected ones)
h.wg.Add(1)
h.txsCh = make(chan core.NewTxsEvent, txChanSize)

View File

@@ -136,7 +136,7 @@ func (p *Peer) dispatchRequest(req *Request) error {
}
}
// dispatchResponse fulfils a pending request and delivers it to the requested
// dispatchRequest fulfils a pending request and delivers it to the requested
// sink.
func (p *Peer) dispatchResponse(res *Response, metadata func() interface{}) error {
resOp := &response{

View File

@@ -71,7 +71,7 @@ func (eth *Ethereum) hashState(ctx context.Context, block *types.Block, reexec u
// the internal junks created by tracing will be persisted into the disk.
// TODO(rjl493456442), clean cache is disabled to prevent memory leak,
// please re-enable it for better performance.
database = state.NewDatabaseWithConfig(eth.chainDb, triedb.HashDefaults)
database = state.NewDatabaseWithConfig(eth.chainDb, triedb.HashDefaults, false)
if statedb, err = state.New(block.Root(), database, nil); err == nil {
log.Info("Found disk backend for state trie", "root", block.Root(), "number", block.Number())
return statedb, noopReleaser, nil
@@ -92,7 +92,7 @@ func (eth *Ethereum) hashState(ctx context.Context, block *types.Block, reexec u
// TODO(rjl493456442), clean cache is disabled to prevent memory leak,
// please re-enable it for better performance.
tdb = triedb.NewDatabase(eth.chainDb, triedb.HashDefaults)
database = state.NewDatabaseWithNodeDB(eth.chainDb, tdb)
database = state.NewDatabaseWithNodeDB(eth.chainDb, tdb, false)
// If we didn't check the live database, do check state over ephemeral database,
// otherwise we would rewind past a persisted block (specific corner case is
@@ -221,6 +221,7 @@ func (eth *Ethereum) stateAtBlock(ctx context.Context, block *types.Block, reexe
if eth.blockchain.TrieDB().Scheme() == rawdb.HashScheme {
return eth.hashState(ctx, block, reexec, base, readOnly, preferDisk)
}
// path and version schema use the same interface
return eth.pathState(block)
}

View File

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

View File

@@ -131,8 +131,8 @@ func (ec *Client) BlockReceipts(ctx context.Context, blockNrOrHash rpc.BlockNumb
}
// BlobSidecars return the Sidecars of a given block number or hash.
func (ec *Client) BlobSidecars(ctx context.Context, blockNrOrHash rpc.BlockNumberOrHash) ([]*types.BlobSidecar, error) {
var r []*types.BlobSidecar
func (ec *Client) BlobSidecars(ctx context.Context, blockNrOrHash rpc.BlockNumberOrHash) ([]*types.BlobTxSidecar, error) {
var r []*types.BlobTxSidecar
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.BlobSidecar, error) {
var r *types.BlobSidecar
func (ec *Client) BlobSidecarByTxHash(ctx context.Context, hash common.Hash) (*types.BlobTxSidecar, error) {
var r *types.BlobTxSidecar
err := ec.c.CallContext(ctx, &r, "eth_getBlobSidecarByTxHash", hash)
if err == nil && r == nil {
return nil, ethereum.NotFound
@@ -361,7 +361,7 @@ func (ec *Client) TransactionInBlock(ctx context.Context, blockHash common.Hash,
return json.tx, err
}
// TransactionsInBlock returns a single transaction at index in the given block.
// TransactionInBlock returns a single transaction at index in the given block.
func (ec *Client) TransactionsInBlock(ctx context.Context, number *big.Int) ([]*types.Transaction, error) {
var rpcTxs []*rpcTransaction
err := ec.c.CallContext(ctx, &rpcTxs, "eth_getTransactionsByBlockNumber", toBlockNumArg(number))
@@ -376,7 +376,7 @@ func (ec *Client) TransactionsInBlock(ctx context.Context, number *big.Int) ([]*
return txs, err
}
// TransactionRecipientsInBlock returns a single transaction at index in the given block.
// TransactionInBlock returns a single transaction at index in the given block.
func (ec *Client) TransactionRecipientsInBlock(ctx context.Context, number *big.Int) ([]*types.Receipt, error) {
var rs []*types.Receipt
err := ec.c.CallContext(ctx, &rs, "eth_getTransactionReceiptsByBlockNumber", toBlockNumArg(number))

26
go.mod
View File

@@ -12,6 +12,7 @@ require (
github.com/aws/aws-sdk-go-v2/service/route53 v1.30.2
github.com/bnb-chain/fastssz v0.1.2
github.com/bnb-chain/ics23 v0.1.0
github.com/bnb-chain/versioned-state-database v0.0.0-00010101000000-000000000000
github.com/btcsuite/btcd/btcec/v2 v2.3.2
github.com/cespare/cp v1.1.1
github.com/cloudflare/cloudflare-go v0.79.0
@@ -27,6 +28,7 @@ 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
@@ -43,7 +45,7 @@ require (
github.com/hashicorp/golang-lru v0.5.5-0.20210104140557-80c98217689d
github.com/holiman/billy v0.0.0-20240216141850-2abb0c79d3c4
github.com/holiman/bloomfilter/v2 v2.0.3
github.com/holiman/uint256 v1.2.4
github.com/holiman/uint256 v1.3.0
github.com/huin/goupnp v1.3.0
github.com/influxdata/influxdb-client-go/v2 v2.4.0
github.com/influxdata/influxdb1-client v0.0.0-20220302092344-a9ab5670611c
@@ -66,7 +68,7 @@ require (
github.com/rs/cors v1.8.2
github.com/shirou/gopsutil v3.21.11+incompatible
github.com/status-im/keycard-go v0.2.0
github.com/stretchr/testify v1.8.4
github.com/stretchr/testify v1.9.0
github.com/supranational/blst v0.3.11
github.com/syndtr/goleveldb v1.0.1
github.com/tendermint/go-amino v0.14.1
@@ -78,13 +80,13 @@ require (
github.com/wealdtech/go-eth2-wallet-encryptor-keystorev4 v1.1.3
github.com/willf/bitset v1.1.3
go.uber.org/automaxprocs v1.5.2
golang.org/x/crypto v0.21.0
golang.org/x/crypto v0.25.0
golang.org/x/exp v0.0.0-20240213143201-ec583247a57a
golang.org/x/sync v0.6.0
golang.org/x/sys v0.20.0
golang.org/x/text v0.14.0
golang.org/x/sync v0.7.0
golang.org/x/sys v0.22.0
golang.org/x/text v0.16.0
golang.org/x/time v0.5.0
golang.org/x/tools v0.18.0
golang.org/x/tools v0.21.1-0.20240508182429-e35e4ccd0d2d
gopkg.in/natefinch/lumberjack.v2 v2.0.0
gopkg.in/yaml.v3 v3.0.1
)
@@ -110,7 +112,7 @@ require (
github.com/beorn7/perks v1.0.1 // indirect
github.com/bits-and-blooms/bitset v1.11.0 // indirect
github.com/cespare/xxhash v1.1.0 // indirect
github.com/cespare/xxhash/v2 v2.2.0 // indirect
github.com/cespare/xxhash/v2 v2.3.0 // indirect
github.com/chzyer/readline v1.5.1 // indirect
github.com/cockroachdb/errors v1.11.1 // indirect
github.com/cockroachdb/logtags v0.0.0-20230118201751-21c54148d20b // indirect
@@ -250,6 +252,7 @@ require (
github.com/spf13/afero v1.10.0 // indirect
github.com/tecbot/gorocksdb v0.0.0-20191217155057-f0fad39f321c // indirect
github.com/thomaso-mirodin/intmath v0.0.0-20160323211736-5dc6d854e46e // indirect
github.com/tidwall/btree v1.7.0 // indirect
github.com/tidwall/gjson v1.10.2 // indirect
github.com/tidwall/match v1.1.1 // indirect
github.com/tidwall/pretty v1.2.0 // indirect
@@ -270,10 +273,10 @@ require (
go.uber.org/mock v0.4.0 // indirect
go.uber.org/multierr v1.11.0 // indirect
go.uber.org/zap v1.27.0 // indirect
golang.org/x/mod v0.15.0 // indirect
golang.org/x/net v0.23.0 // indirect
golang.org/x/mod v0.17.0 // indirect
golang.org/x/net v0.25.0 // indirect
golang.org/x/oauth2 v0.16.0 // indirect
golang.org/x/term v0.18.0 // indirect
golang.org/x/term v0.22.0 // indirect
google.golang.org/api v0.44.0 // indirect
google.golang.org/appengine v1.6.7 // indirect
google.golang.org/genproto v0.0.0-20231016165738-49dd2c1f3d0b // indirect
@@ -294,6 +297,7 @@ require (
)
replace (
github.com/bnb-chain/versioned-state-database => ../versioned-state-database
github.com/cometbft/cometbft => github.com/bnb-chain/greenfield-cometbft v1.3.1
github.com/grpc-ecosystem/grpc-gateway/v2 => github.com/prysmaticlabs/grpc-gateway/v2 v2.3.1-0.20210702154020-550e1cd83ec1
github.com/syndtr/goleveldb v1.0.1 => github.com/syndtr/goleveldb v1.0.1-0.20210819022825-2ae1ddf74ef7

50
go.sum
View File

@@ -185,8 +185,9 @@ github.com/cespare/cp v1.1.1/go.mod h1:SOGHArjBr4JWaSDEVpWpo/hNg6RoKrls6Oh40hiwW
github.com/cespare/xxhash v1.1.0 h1:a6HrQnmkObjyL+Gs60czilIUGqrzKutQD6XZog3p+ko=
github.com/cespare/xxhash v1.1.0/go.mod h1:XrSqR1VqqWfGrhpAt58auRo0WTKS1nRRg3ghfAqPWnc=
github.com/cespare/xxhash/v2 v2.1.1/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=
github.com/cespare/xxhash/v2 v2.2.0 h1:DC2CZ1Ep5Y4k3ZQ899DldepgrayRUGE6BBZ/cd9Cj44=
github.com/cespare/xxhash/v2 v2.2.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=
github.com/cespare/xxhash/v2 v2.3.0 h1:UL815xU9SqsFlibzuggzjXhog7bL6oX9BbNZnL2UFvs=
github.com/cespare/xxhash/v2 v2.3.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=
github.com/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWRnGsAI=
github.com/chzyer/logex v1.2.0/go.mod h1:9+9sk7u7pGNWYMkh0hdiL++6OeibzJccyQU4p4MedaY=
github.com/chzyer/logex v1.2.1 h1:XHDu3E6q+gdHgsdTPH6ImJMIp436vR6MPtH8gP05QzM=
@@ -335,6 +336,8 @@ github.com/ferranbt/fastssz v0.0.0-20210905181407-59cf6761a7d5 h1:6dVcS0LktRSyEE
github.com/ferranbt/fastssz v0.0.0-20210905181407-59cf6761a7d5/go.mod h1:S8yiDeAXy8f88W4Ul+0dBMPx49S05byYbmZD6Uv94K4=
github.com/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=
@@ -611,8 +614,8 @@ github.com/holiman/billy v0.0.0-20240216141850-2abb0c79d3c4 h1:X4egAf/gcS1zATw6w
github.com/holiman/billy v0.0.0-20240216141850-2abb0c79d3c4/go.mod h1:5GuXa7vkL8u9FkFuWdVvfR5ix8hRB7DbOAaYULamFpc=
github.com/holiman/bloomfilter/v2 v2.0.3 h1:73e0e/V0tCydx14a0SCYS/EWCxgwLZ18CZcZKVu0fao=
github.com/holiman/bloomfilter/v2 v2.0.3/go.mod h1:zpoh+gs7qcpqrHr3dB55AMiJwo0iURXE7ZOP9L9hSkA=
github.com/holiman/uint256 v1.2.4 h1:jUc4Nk8fm9jZabQuqr2JzednajVmBpC+oiTiXZJEApU=
github.com/holiman/uint256 v1.2.4/go.mod h1:EOMSn4q6Nyt9P6efbI3bueV4e1b3dGlUCXeiRV4ng7E=
github.com/holiman/uint256 v1.3.0 h1:4wdcm/tnd0xXdu7iS3ruNvxkWwrb4aeBQv19ayYn8F4=
github.com/holiman/uint256 v1.3.0/go.mod h1:EOMSn4q6Nyt9P6efbI3bueV4e1b3dGlUCXeiRV4ng7E=
github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU=
github.com/hudl/fargo v1.3.0/go.mod h1:y3CKSmjA+wD2gak7sUSXTAoopbhU08POFhmITJgmKTg=
github.com/huin/goupnp v1.3.0 h1:UvLUlWDNpoUdYzb2TCn+MuTWtcjXKSza2n6CBdQ0xXc=
@@ -1118,8 +1121,9 @@ github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+
github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/objx v0.2.0/go.mod h1:qt09Ya8vawLte6SNmTgCsAVtYtaKzEcn8ATUoHMkEqE=
github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw=
github.com/stretchr/objx v0.5.0 h1:1zr/of2m5FGMsad5YfcqgdqdWrIhu+EBEJRhR1U7z/c=
github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo=
github.com/stretchr/objx v0.5.2 h1:xuMeJ0Sdp5ZMRXx/aWO6RZxdr3beISkG5/G/aIRr3pY=
github.com/stretchr/objx v0.5.2/go.mod h1:FRsXN1f5AsAjCGJKqEizvkpNtU+EGNCLh3NxZ/8L+MA=
github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=
@@ -1130,8 +1134,8 @@ github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/
github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU=
github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4=
github.com/stretchr/testify v1.8.2/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4=
github.com/stretchr/testify v1.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcUk=
github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo=
github.com/stretchr/testify v1.9.0 h1:HtqpIVDClZ4nwg75+f6Lvsy/wHu+3BoSGCbBAcpTsTg=
github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY=
github.com/subosito/gotenv v1.2.0/go.mod h1:N0PQaV/YGNqwC0u51sEeR/aUtSLEXKX9iv69rRypqCw=
github.com/supranational/blst v0.3.11 h1:LyU6FolezeWAhvQk0k6O/d49jqgO52MSDDfYgbeoEm4=
github.com/supranational/blst v0.3.11/go.mod h1:jZJtfjgudtNl4en1tzwPIV3KjUnQUvG3/j+w+fVonLw=
@@ -1148,6 +1152,8 @@ github.com/tendermint/iavl v0.12.0 h1:xcaFAr+ycqCj7WN1RzL2EfcBioRDOHcU1oWcg83K02
github.com/tendermint/iavl v0.12.0/go.mod h1:EoKMMv++tDOL5qKKVnoIqtVPshRrEPeJ0WsgDOLAauM=
github.com/thomaso-mirodin/intmath v0.0.0-20160323211736-5dc6d854e46e h1:cR8/SYRgyQCt5cNCMniB/ZScMkhI9nk8U5C7SbISXjo=
github.com/thomaso-mirodin/intmath v0.0.0-20160323211736-5dc6d854e46e/go.mod h1:Tu4lItkATkonrYuvtVjG0/rhy15qrNGNTjPdaphtZ/8=
github.com/tidwall/btree v1.7.0 h1:L1fkJH/AuEh5zBnnBbmTwQ5Lt+bRJ5A8EWecslvo9iI=
github.com/tidwall/btree v1.7.0/go.mod h1:twD9XRA5jj9VUQGELzDO4HPQTNJsoWWfYEL+EUQ2cKY=
github.com/tidwall/gjson v1.10.2 h1:APbLGOM0rrEkd8WBw9C24nllro4ajFuJu0Sc9hRz8Bo=
github.com/tidwall/gjson v1.10.2/go.mod h1:/wbyibRr2FHMks5tjHJ5F8dMZh3AcwJEMf5vlfC0lxk=
github.com/tidwall/match v1.1.1 h1:+Ho715JplO36QYgwN9PGYNhgZvoUSc9X2c80KVTi+GA=
@@ -1283,8 +1289,8 @@ golang.org/x/crypto v0.0.0-20210322153248-0c34fe9e7dc2/go.mod h1:T9bdIzuCu7OtxOm
golang.org/x/crypto v0.0.0-20210421170649-83a5a9bb288b/go.mod h1:T9bdIzuCu7OtxOm1hfPfRQxPLYneinmdGuTeoZ9dtd4=
golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
golang.org/x/crypto v0.0.0-20220722155217-630584e8d5aa/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4=
golang.org/x/crypto v0.21.0 h1:X31++rzVUdKhX5sWmSOFZxx8UW/ldWx55cbf08iNAMA=
golang.org/x/crypto v0.21.0/go.mod h1:0BP7YvVV9gBbVKyeTG0Gyn+gZm94bibOW5BjDEYAOMs=
golang.org/x/crypto v0.25.0 h1:ypSNr+bnYL2YhwoMt2zPxHFmbAN1KZs/njMG3hxUp30=
golang.org/x/crypto v0.25.0/go.mod h1:T+wALwcMOSE0kXgUAnPAHqTLW+XHgcELELW8VaDgm/M=
golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8=
@@ -1323,8 +1329,8 @@ golang.org/x/mod v0.4.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
golang.org/x/mod v0.4.1/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4=
golang.org/x/mod v0.15.0 h1:SernR4v+D55NyBH2QiEQrlBAnj1ECL6AGrA5+dPaMY8=
golang.org/x/mod v0.15.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c=
golang.org/x/mod v0.17.0 h1:zY54UmvipHiNd+pm+m0x9KhZ9hl1/7QNMyxXbc6ICqA=
golang.org/x/mod v0.17.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c=
golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
@@ -1376,8 +1382,8 @@ golang.org/x/net v0.0.0-20210316092652-d523dce5a7f4/go.mod h1:RBQZq4jEuRlivfhVLd
golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM=
golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c=
golang.org/x/net v0.23.0 h1:7EYJ93RZ9vYSZAIb2x3lnuvqO5zneoD6IvWjuhfxjTs=
golang.org/x/net v0.23.0/go.mod h1:JKghWKKOSdJwpW2GEx0Ja7fmaKnMsbu+MWVZTokSYmg=
golang.org/x/net v0.25.0 h1:d/OCCoBEUq33pjydKrGQhw7IlUPI2Oylr+8qLx49kac=
golang.org/x/net v0.25.0/go.mod h1:JkAGAh7GEvH74S6FOH42FLoXpXbE/aqXSrIQjXgsiwM=
golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
golang.org/x/oauth2 v0.0.0-20181017192945-9dcd33a902f4/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
golang.org/x/oauth2 v0.0.0-20181203162652-d668ce993890/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
@@ -1408,8 +1414,8 @@ golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJ
golang.org/x/sync v0.0.0-20201207232520-09787c993a3a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.6.0 h1:5BMeUDZ7vkXGfEr1x9B4bRcTH4lpkTkpdh0T/J+qjbQ=
golang.org/x/sync v0.6.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
golang.org/x/sync v0.7.0 h1:YsImfSBoP9QPYL0xyKJPq0gcaJdG3rInoqxTWbfQu9M=
golang.org/x/sync v0.7.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
golang.org/x/sys v0.0.0-20180810173357-98c5dad5d1a0/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20180823144017-11551d06cbcc/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
@@ -1500,13 +1506,13 @@ golang.org/x/sys v0.1.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.14.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
golang.org/x/sys v0.20.0 h1:Od9JTbYCk261bKm4M/mw7AklTlFYIa0bIp9BgSm1S8Y=
golang.org/x/sys v0.20.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
golang.org/x/sys v0.22.0 h1:RI27ohtqKCnwULzJLqkv897zojh5/DwS/ENaMzUOaWI=
golang.org/x/sys v0.22.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
golang.org/x/term v0.0.0-20201117132131-f5c789dd3221/go.mod h1:Nr5EML6q2oocZ2LXRh80K7BxOlk5/8JxuGnuhpl+muw=
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
golang.org/x/term v0.18.0 h1:FcHjZXDMxI8mM3nwhX9HlKop4C0YQvCVCdwYl2wOtE8=
golang.org/x/term v0.18.0/go.mod h1:ILwASektA3OnRv7amZ1xhE/KTR+u50pbXfZ03+6Nx58=
golang.org/x/term v0.22.0 h1:BbsgPEJULsl2fV/AT3v15Mjva5yXKQDyKf+TbDz7QJk=
golang.org/x/term v0.22.0/go.mod h1:F3qCibpT5AMpCRfhfT53vVJwhLtIVHhB9XDjfFvnMI4=
golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
@@ -1517,8 +1523,8 @@ golang.org/x/text v0.3.5/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ=
golang.org/x/text v0.3.8/go.mod h1:E6s5w1FMmriuDzIBO73fBruAKo1PCIq6d2Q6DHfQ8WQ=
golang.org/x/text v0.14.0 h1:ScX5w1eTa3QqT8oi6+ziP7dTV1S2+ALU0bI+0zXKWiQ=
golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU=
golang.org/x/text v0.16.0 h1:a94ExnEXNtEwYLGJSIUxnWoxoRz/ZcCsV63ROupILh4=
golang.org/x/text v0.16.0/go.mod h1:GhwF1Be+LQoKShO3cGOHzqOgRrGaYc9AvblQOmPVHnI=
golang.org/x/time v0.0.0-20180412165947-fbb02b2291d2/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
@@ -1592,8 +1598,8 @@ golang.org/x/tools v0.0.0-20210108195828-e2f9c7f1fc8e/go.mod h1:emZCQorbCU4vsT4f
golang.org/x/tools v0.1.0/go.mod h1:xkSsbof2nBLbhDlRMhhhyNLN/zl3eTqcnHD5viDpcZ0=
golang.org/x/tools v0.1.5/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk=
golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc=
golang.org/x/tools v0.18.0 h1:k8NLag8AGHnn+PHbl7g43CtqZAwG60vZkLqgyZgIHgQ=
golang.org/x/tools v0.18.0/go.mod h1:GL7B4CwcLLeo59yx/9UWWuNOW1n3VZ4f5axWfML7Lcg=
golang.org/x/tools v0.21.1-0.20240508182429-e35e4ccd0d2d h1:vU5i/LfpvrRCpgM/VPfJLg5KjxD3E+hfT1SH+d9zLwg=
golang.org/x/tools v0.21.1-0.20240508182429-e35e4ccd0d2d/go.mod h1:aiJjzUbINMkxbQROHiO6hDPo2LHcIPhhQsa9DLh0yGk=
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=

View File

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

View File

@@ -862,72 +862,48 @@ func (s *BlockChainAPI) Health() bool {
return true
}
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")
}
curValidators, err := s.b.CurrentValidators()
if err != nil { // impossible
return 0, err
}
valLen := int64(len(curValidators))
if verifiedValidatorNum < 1 || verifiedValidatorNum > valLen {
return 0, fmt.Errorf("%d out of range [1,%d]", verifiedValidatorNum, valLen)
// 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)
}
var err error
fastFinalizedHeader, err := s.b.HeaderByNumber(ctx, rpc.FinalizedBlockNumber)
if err != nil { // impossible
return 0, err
}
latestHeader, err := s.b.HeaderByNumber(ctx, rpc.LatestBlockNumber)
if err != nil { // impossible
return 0, err
}
lastHeader := latestHeader
confirmedValSet := make(map[common.Address]struct{}, valLen)
confirmedValSet[lastHeader.Coinbase] = struct{}{}
for count := 1; int64(len(confirmedValSet)) < verifiedValidatorNum && count <= int(parliaConfig.Epoch) && lastHeader.Number.Int64() > max(fastFinalizedHeader.Number.Int64(), 1); count++ {
lastHeader, err = s.b.HeaderByHash(ctx, lastHeader.ParentHash)
if err != nil { // impossible
return 0, err
}
confirmedValSet[lastHeader.Coinbase] = struct{}{}
}
finalizedBlockNumber := max(fastFinalizedHeader.Number.Int64(), lastHeader.Number.Int64())
log.Debug("getFinalizedNumber", "LatestBlockNumber", latestHeader.Number.Int64(), "fastFinalizedHeight", fastFinalizedHeader.Number.Int64(),
"lastHeader", lastHeader.Number.Int64(), "finalizedBlockNumber", finalizedBlockNumber, "len(confirmedValSet)", len(confirmedValSet))
return finalizedBlockNumber, nil
}
// GetFinalizedHeader returns the finalized block header based on the specified parameters.
// - `verifiedValidatorNum` must be within the range [1, len(currentValidators)].
// - The function calculates `probabilisticFinalizedHeight` as the highest height of the block verified by `verifiedValidatorNum` validators,
// it then returns the block header with a height equal to `max(fastFinalizedHeight, probabilisticFinalizedHeight)`.
// - The height of the returned block header is guaranteed to be monotonically increasing.
func (s *BlockChainAPI) GetFinalizedHeader(ctx context.Context, verifiedValidatorNum int64) (map[string]interface{}, error) {
finalizedBlockNumber, err := s.getFinalizedNumber(ctx, verifiedValidatorNum)
if err != nil { // impossible
return nil, err
}
latestHeader, err := s.b.HeaderByNumber(ctx, rpc.LatestBlockNumber)
if err != nil { // impossible
return nil, err
}
finalizedBlockNumber := max(fastFinalizedHeader.Number.Int64(), latestHeader.Number.Int64()-probabilisticFinalized)
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)
// 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)
}
var err error
fastFinalizedHeader, err := s.b.HeaderByNumber(ctx, rpc.FinalizedBlockNumber)
if err != nil { // impossible
return nil, err
}
latestHeader, err := s.b.HeaderByNumber(ctx, rpc.LatestBlockNumber)
if err != nil { // impossible
return nil, err
}
finalizedBlockNumber := max(fastFinalizedHeader.Number.Int64(), latestHeader.Number.Int64()-probabilisticFinalized)
return s.GetBlockByNumber(ctx, rpc.BlockNumber(finalizedBlockNumber), fullTx)
}

View File

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

View File

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

View File

@@ -416,8 +416,6 @@ func (b *backendMock) SubscribeRemovedLogsEvent(ch chan<- core.RemovedLogsEvent)
func (b *backendMock) Engine() consensus.Engine { return 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 }
func (b *backendMock) MevParams() *types.MevParams {

View File

@@ -18,7 +18,6 @@ import (
"github.com/ethereum/go-ethereum/common/bidutil"
"github.com/ethereum/go-ethereum/consensus"
"github.com/ethereum/go-ethereum/core"
"github.com/ethereum/go-ethereum/core/txpool"
"github.com/ethereum/go-ethereum/core/types"
"github.com/ethereum/go-ethereum/event"
"github.com/ethereum/go-ethereum/log"
@@ -83,7 +82,6 @@ type bidSimulator struct {
delayLeftOver time.Duration
minGasPrice *big.Int
chain *core.BlockChain
txpool *txpool.TxPool
chainConfig *params.ChainConfig
engine consensus.Engine
bidWorker bidWorker
@@ -120,7 +118,7 @@ func newBidSimulator(
config *MevConfig,
delayLeftOver time.Duration,
minGasPrice *big.Int,
eth Backend,
chain *core.BlockChain,
chainConfig *params.ChainConfig,
engine consensus.Engine,
bidWorker bidWorker,
@@ -129,8 +127,7 @@ func newBidSimulator(
config: config,
delayLeftOver: delayLeftOver,
minGasPrice: minGasPrice,
chain: eth.BlockChain(),
txpool: eth.TxPool(),
chain: chain,
chainConfig: chainConfig,
engine: engine,
bidWorker: bidWorker,
@@ -144,7 +141,7 @@ func newBidSimulator(
simulatingBid: make(map[common.Hash]*BidRuntime),
}
b.chainHeadSub = b.chain.SubscribeChainHeadEvent(b.chainHeadCh)
b.chainHeadSub = chain.SubscribeChainHeadEvent(b.chainHeadCh)
if config.Enabled {
b.bidReceiving.Store(true)
@@ -412,7 +409,7 @@ func (b *bidSimulator) clearLoop() {
}
delete(b.bestBid, parentHash)
for k, v := range b.bestBid {
if v.bid.BlockNumber <= blockNumber-b.chain.TriesInMemory() {
if v.bid.BlockNumber <= blockNumber-core.TriesInMemory {
v.env.discard()
delete(b.bestBid, k)
}
@@ -421,7 +418,7 @@ func (b *bidSimulator) clearLoop() {
b.simBidMu.Lock()
for k, v := range b.simulatingBid {
if v.bid.BlockNumber <= blockNumber-b.chain.TriesInMemory() {
if v.bid.BlockNumber <= blockNumber-core.TriesInMemory {
v.env.discard()
delete(b.simulatingBid, k)
}
@@ -628,41 +625,18 @@ func (b *bidSimulator) simBid(interruptCh chan int32, bidRuntime *BidRuntime) {
// check if bid gas price is lower than min gas price
{
bidGasUsed := uint64(0)
bidGasFee := big.NewInt(0)
bidGasFee := bidRuntime.env.state.GetBalance(consensus.SystemAddress)
for i, receipt := range bidRuntime.env.receipts {
tx := bidRuntime.env.txs[i]
if !b.txpool.Has(tx.Hash()) {
for _, receipt := range bidRuntime.env.receipts {
bidGasUsed += receipt.GasUsed
effectiveTip, er := tx.EffectiveGasTip(bidRuntime.env.header.BaseFee)
if er != nil {
err = errors.New("failed to calculate effective tip")
return
}
if bidRuntime.env.header.BaseFee != nil {
effectiveTip.Add(effectiveTip, bidRuntime.env.header.BaseFee)
}
gasFee := new(big.Int).Mul(effectiveTip, new(big.Int).SetUint64(receipt.GasUsed))
bidGasFee.Add(bidGasFee, gasFee)
if tx.Type() == types.BlobTxType {
blobFee := new(big.Int).Mul(receipt.BlobGasPrice, new(big.Int).SetUint64(receipt.BlobGasUsed))
bidGasFee.Add(bidGasFee, blobFee)
}
}
}
// if bid txs are all from mempool, do not check gas price
if bidGasUsed != 0 {
bidGasPrice := new(big.Int).Div(bidGasFee, new(big.Int).SetUint64(bidGasUsed))
bidGasPrice := new(big.Int).Div(bidGasFee.ToBig(), new(big.Int).SetUint64(bidGasUsed))
if bidGasPrice.Cmp(b.minGasPrice) < 0 {
err = fmt.Errorf("bid gas price is lower than min gas price, bid:%v, min:%v", bidGasPrice, b.minGasPrice)
err = errors.New("bid gas price is lower than min gas price")
return
}
}
}
// if enable greedy merge, fill bid env with transactions from mempool
if b.config.GreedyMergeTx {

View File

@@ -62,7 +62,7 @@ type Config struct {
// DefaultConfig contains default settings for miner.
var DefaultConfig = Config{
GasCeil: 0,
GasCeil: 30000000,
GasPrice: big.NewInt(params.GWei),
// The default recommit time is chosen as two seconds since
@@ -102,7 +102,7 @@ func New(eth Backend, config *Config, chainConfig *params.ChainConfig, mux *even
worker: newWorker(config, chainConfig, engine, eth, mux, isLocalBlock, false),
}
miner.bidSimulator = newBidSimulator(&config.Mev, config.DelayLeftOver, config.GasPrice, eth, chainConfig, engine, miner.worker)
miner.bidSimulator = newBidSimulator(&config.Mev, config.DelayLeftOver, config.GasPrice, eth.BlockChain(), chainConfig, engine, miner.worker)
miner.worker.setBestBidFetcher(miner.bidSimulator)
miner.wg.Add(1)

View File

@@ -1032,8 +1032,6 @@ func (w *worker) prepareWork(genParams *generateParams) (*environment, error) {
}
if w.chainConfig.Parlia == nil {
header.ParentBeaconRoot = genParams.beaconRoot
} else if w.chainConfig.IsBohr(header.Number, header.Time) {
header.ParentBeaconRoot = new(common.Hash)
}
}
// Could potentially happen if starting to mine in an odd state.

View File

@@ -153,8 +153,8 @@ var (
FeynmanFixTime: newUint64(1713419340), // 2024-04-18 05:49:00 AM UTC
CancunTime: newUint64(1718863500), // 2024-06-20 06:05:00 AM UTC
HaberTime: newUint64(1718863500), // 2024-06-20 06:05:00 AM UTC
HaberFixTime: newUint64(1727316120), // 2024-09-26 02:02:00 AM UTC
BohrTime: newUint64(1727317200), // 2024-09-26 02:20:00 AM UTC
HaberFixTime: nil, // TBD
BohrTime: nil,
Parlia: &ParliaConfig{
Period: 3,
@@ -195,7 +195,7 @@ var (
CancunTime: newUint64(1713330442), // 2024-04-17 05:07:22 AM UTC
HaberTime: newUint64(1716962820), // 2024-05-29 06:07:00 AM UTC
HaberFixTime: newUint64(1719986788), // 2024-07-03 06:06:28 AM UTC
BohrTime: newUint64(1724116996), // 2024-08-20 01:23:16 AM UTC
BohrTime: nil,
Parlia: &ParliaConfig{
Period: 3,

View File

@@ -192,11 +192,6 @@ var (
MinBlocksForBlobRequests uint64 = 524288 // it keeps blob data available for ~18.2 days in local, ref: https://github.com/bnb-chain/BEPs/blob/master/BEPs/BEP-336.md#51-parameters.
DefaultExtraReserveForBlobRequests uint64 = 1 * (24 * 3600) / 3 // it adds more time for expired blobs for some request cases, like expiry blob when remote peer is syncing, default 1 day.
BreatheBlockInterval uint64 = 86400 // Controls the interval for updateValidatorSetV2
// used for testing:
// [1,9] except 2 --> used as turn length directly
// 2 --> use random values to test switching turn length
// 0 and other values --> get turn length from contract
FixedTurnLength uint64 = 0
)
// Gas discount table for BLS12-381 G1 and G2 multi exponentiation operations

View File

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

View File

@@ -1,19 +1,8 @@
From 32329440626abd6e9668c2d5bd2e7b719e951e01 Mon Sep 17 00:00:00 2001
From: NathanBSC <Nathan.l@nodereal.io>
Date: Wed, 31 Jul 2024 15:01:28 +0800
Subject: [PATCH] diff go ethereum
---
core/vm/contracts.go | 10 ----------
core/vm/jump_table.go | 2 +-
params/protocol_params.go | 2 +-
3 files changed, 2 insertions(+), 12 deletions(-)
diff --git a/core/vm/contracts.go b/core/vm/contracts.go
index 38a6cac24..7eb29c3ed 100644
index 5988bb15f..c92cbf542 100644
--- a/core/vm/contracts.go
+++ b/core/vm/contracts.go
@@ -84,9 +84,6 @@ var PrecompiledContractsIstanbul = map[common.Address]PrecompiledContract{
@@ -83,9 +83,6 @@ var PrecompiledContractsIstanbul = map[common.Address]PrecompiledContract{
common.BytesToAddress([]byte{7}): &bn256ScalarMulIstanbul{},
common.BytesToAddress([]byte{8}): &bn256PairingIstanbul{},
common.BytesToAddress([]byte{9}): &blake2F{},
@@ -23,7 +12,7 @@ index 38a6cac24..7eb29c3ed 100644
}
var PrecompiledContractsNano = map[common.Address]PrecompiledContract{
@@ -239,13 +236,6 @@ var PrecompiledContractsCancun = map[common.Address]PrecompiledContract{
@@ -238,13 +235,6 @@ var PrecompiledContractsCancun = map[common.Address]PrecompiledContract{
common.BytesToAddress([]byte{8}): &bn256PairingIstanbul{},
common.BytesToAddress([]byte{9}): &blake2F{},
common.BytesToAddress([]byte{0x0a}): &kzgPointEvaluation{},
@@ -36,7 +25,7 @@ index 38a6cac24..7eb29c3ed 100644
- common.BytesToAddress([]byte{105}): &secp256k1SignatureRecover{},
}
// PrecompiledContractsHaber contains the default set of pre-compiled Ethereum
// PrecompiledContractsBLS contains the set of pre-compiled Ethereum
diff --git a/core/vm/jump_table.go b/core/vm/jump_table.go
index 70c543f14..65716f944 100644
--- a/core/vm/jump_table.go
@@ -51,7 +40,7 @@ index 70c543f14..65716f944 100644
enable3860(&instructionSet) // Limit and meter initcode
diff --git a/params/protocol_params.go b/params/protocol_params.go
index 65b2d942c..bb085512f 100644
index b84fa148f..97bf6c4d2 100644
--- a/params/protocol_params.go
+++ b/params/protocol_params.go
@@ -23,7 +23,7 @@ import (
@@ -63,6 +52,3 @@ index 65b2d942c..bb085512f 100644
MinGasLimit uint64 = 5000 // Minimum the gas limit may ever be.
MaxGasLimit uint64 = 0x7fffffffffffffff // Maximum the gas limit (2^63-1).
GenesisGasLimit uint64 = 4712388 // Gas limit of the Genesis block.
--
2.41.0

View File

@@ -11,5 +11,4 @@ echo "PASS",$PASS,"FAIL",$FAIL
if [ $FAIL -ne 0 ]
then
cat fail.log
exit 1
fi

View File

@@ -20,6 +20,7 @@ import (
"errors"
"strings"
versa "github.com/bnb-chain/versioned-state-database"
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/core/rawdb"
"github.com/ethereum/go-ethereum/ethdb"
@@ -30,6 +31,7 @@ import (
"github.com/ethereum/go-ethereum/triedb/database"
"github.com/ethereum/go-ethereum/triedb/hashdb"
"github.com/ethereum/go-ethereum/triedb/pathdb"
"github.com/ethereum/go-ethereum/triedb/versiondb"
)
// Config defines all necessary options for database.
@@ -38,6 +40,8 @@ type Config struct {
Cache int
NoTries bool
IsVerkle bool // Flag whether the db is holding a verkle tree
IsVersion bool
VersionDB *versiondb.Config
HashDB *hashdb.Config // Configs for hash-based scheme
PathDB *pathdb.Config // Configs for experimental path-based scheme
}
@@ -92,6 +96,16 @@ type Database struct {
// NewDatabase initializes the trie database with default settings, note
// the legacy hash-based scheme is used by default.
func NewDatabase(diskdb ethdb.Database, config *Config) *Database {
if config != nil && config.IsVersion {
// TODO:: Wait for debugging to stabilize, and then consider initialization compatibility with other databases
db := &Database{
config: config,
diskdb: diskdb,
backend: versiondb.New(config.VersionDB),
}
return db
}
// Sanitize the config and use the default one if it's not specified.
var triediskdb ethdb.Database
if diskdb != nil && diskdb.StateStore() != nil {
@@ -409,3 +423,12 @@ func (db *Database) GetAllRooHash() [][]string {
func (db *Database) IsVerkle() bool {
return db.config.IsVerkle
}
// VersaDB returns versioned database instance, it is useless for hashdb and pathdb
func (db *Database) VersaDB() versa.Database {
vdb, ok := db.backend.(*versiondb.VersionDB)
if !ok {
log.Crit("only version db support")
}
return vdb.VersaDB()
}

View File

@@ -139,6 +139,7 @@ func New(diskdb ethdb.Database, config *Config, resolver ChildResolver) *Databas
if config.CleanCacheSize > 0 {
cleans = fastcache.New(config.CleanCacheSize)
}
log.Info("success to init hash mode triedb")
return &Database{
diskdb: diskdb,
resolver: resolver,

View File

@@ -226,6 +226,7 @@ func New(diskdb ethdb.Database, config *Config) *Database {
log.Crit("Failed to disable database", "err", err) // impossible to happen
}
}
log.Info("success to init path mode triedb")
return db
}

Some files were not shown because too many files have changed in this diff Show More