diff --git a/CHANGELOG.md b/CHANGELOG.md index 1b7bcd4637..87d62b1b43 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,4 +1,96 @@ # Changelog +## v1.7.6 +v1.7.6 is for BSC Chapel testnet [Pasteur hardfork](https://github.com/bnb-chain/BEPs/blob/master/BEPs/BEP-673.md),the hard fork time is 2026-07-XX 02:30:00 AM UTC + +### Pasteur Hardfork +- [\#3623](https://github.com/bnb-chain/bsc/pull/3623) core/vm: reject duplicate bridge validators at Pasteur +- [\#3691](https://github.com/bnb-chain/bsc/pull/3691) miner: support builder-proposed block with validator blind signing +- [\#3717](https://github.com/bnb-chain/bsc/pull/3717) params: move Pasteur next to Mendel +- [\#3721](https://github.com/bnb-chain/bsc/pull/3721) core/systemcontracts: introduce Pasteur hardfork system-contract upgrade +- [\#3727](https://github.com/bnb-chain/bsc/pull/3727) core/systemcontracts: point Pasteur CommitUrl to genesis-contract v1.2.6 +- [\#3741](https://github.com/bnb-chain/bsc/pull/3741) miner: disable BidBlock on hard-fork activation blocks +- [\#3742](https://github.com/bnb-chain/bsc/pull/3742) miner: optimize BidBlock signing hash + +### BUGFIX +- [\#3668](https://github.com/bnb-chain/bsc/pull/3668) eth/handler.go: add verify bal +- [\#3671](https://github.com/bnb-chain/bsc/pull/3671) eth/protocols/bsc: cap GetBlocksByRange response size +- [\#3672](https://github.com/bnb-chain/bsc/pull/3672) eth/protocols/bsc: rate-limit incoming votes by vote count +- [\#3680](https://github.com/bnb-chain/bsc/pull/3680) internal/ethapi: limit number of getProofs keys +- [\#3681](https://github.com/bnb-chain/bsc/pull/3681) internal/ethapi: limit number of calls to eth_simulateV1 +- [\#3682](https://github.com/bnb-chain/bsc/pull/3682) internal/ethapi: fix gas cap for eth_simulateV1 +- [\#3683](https://github.com/bnb-chain/bsc/pull/3683) core: fix txLookupLock mutex leak on error returns in reorg() +- [\#3684](https://github.com/bnb-chain/bsc/pull/3684) cmd, core, eth, tests: prevent state flushing in RPC +- [\#3685](https://github.com/bnb-chain/bsc/pull/3685) core/tracing: fix nonce revert edge case +- [\#3686](https://github.com/bnb-chain/bsc/pull/3686) eth/filters: fix race in pending tx and new heads subscriptions +- [\#3687](https://github.com/bnb-chain/bsc/pull/3687) core, internal/ethapi: fix incorrect max-initcode RPC error mapping +- [\#3688](https://github.com/bnb-chain/bsc/pull/3688) eth/filters: rangeLogs should error on invalid block range +- [\#3689](https://github.com/bnb-chain/bsc/pull/3689) eth/filters: fix race in NewVotes and NewFinalizedHeaders +- [\#3692](https://github.com/bnb-chain/bsc/pull/3692) eth/filters: fix source leak when New Filters +- [\#3700](https://github.com/bnb-chain/bsc/pull/3700) crypto: add hash length check in nocgo VerifySignature +- [\#3701](https://github.com/bnb-chain/bsc/pull/3701) p2p/discover: copy buffer before sending read errors to unhandled +- [\#3702](https://github.com/bnb-chain/bsc/pull/3702) p2p/discover: fix timeout loop early exit when removing expired matchers +- [\#3703](https://github.com/bnb-chain/bsc/pull/3703) eth/tracers/logger: fix exclude address list +- [\#3705](https://github.com/bnb-chain/bsc/pull/3705) eth/protocols/eth: stop serving on unavailable responses +- [\#3706](https://github.com/bnb-chain/bsc/pull/3706) triedb/pathdb: fix lookup sentinel collision with zero disk layer root +- [\#3707](https://github.com/bnb-chain/bsc/pull/3707) eth/tracers: forward OnSystemCall hooks through mux +- [\#3708](https://github.com/bnb-chain/bsc/pull/3708) eth/downloader: drop invalid peers + fix deliver index +- [\#3709](https://github.com/bnb-chain/bsc/pull/3709) core/state: fix StateDB Reader error discarded after Commit +- [\#3710](https://github.com/bnb-chain/bsc/pull/3710) p2p/discover: decouple nodeFeed from Table mutex in waitForNodes +- [\#3711](https://github.com/bnb-chain/bsc/pull/3711) core/rawdb: fix file descriptor leak in freezer error paths +- [\#3712](https://github.com/bnb-chain/bsc/pull/3712) core/rawdb: fsync temp file before rename in copyFrom +- [\#3718](https://github.com/bnb-chain/bsc/pull/3718) fix: nocgo sigToPub hash check + pathdb zero-base regression test + +### IMPROVEMENT +- [\#3669](https://github.com/bnb-chain/bsc/pull/3669) miner: reduce local mining time for last block in one turn +- [\#3694](https://github.com/bnb-chain/bsc/pull/3694) consensus/parlia: extract VerifyUnsealedHeader from verifyHeader +- [\#3736](https://github.com/bnb-chain/bsc/pull/3736) miner: add BidBlock verify metrics + +### CLEAN UP +- [\#3670](https://github.com/bnb-chain/bsc/pull/3670) triedb/pathdb: remove legacy field JournalFilePath +- [\#3678](https://github.com/bnb-chain/bsc/pull/3678) miner: remove optional transaction gas limit cap +- [\#3690](https://github.com/bnb-chain/bsc/pull/3690) all: remove BEP-592 non-consensus block access list +- [\#3716](https://github.com/bnb-chain/bsc/pull/3716) ethdb,trie: remove multidb code from bsc +- [\#3720](https://github.com/bnb-chain/bsc/pull/3720) core/rawdb: cleanup bep-592 bal key related +- [\#3722](https://github.com/bnb-chain/bsc/pull/3722) core/txpool/legacypool: remove overflowpool for txs +- [\#3728](https://github.com/bnb-chain/bsc/pull/3728) beacon, cmd: remove fake-beacon op-stack shim (revert #2678) +- [\#3739](https://github.com/bnb-chain/bsc/pull/3739) core/types: extract bid and block mev info into builder subpackage + +#### Deprecated Flags & Config Fields +The following flags and config fields are removed or deprecated in this release. Please update your node configuration accordingly before upgrading: + +**CLI Flags** + +| Flag | Change | Note | +|---|---|---| +| `--journalfile` | Deprecated (no effect) | Remove from your startup script ([#3670](https://github.com/bnb-chain/bsc/pull/3670)) | +| `--miner.txgaslimit` | Deprecated (no effect) | Per-transaction gas limit is now enforced by EIP-7825 ([#3678](https://github.com/bnb-chain/bsc/pull/3678)) | +| `--enablebal` | Deprecated (no effect) | BEP-592 block access list has been removed ([#3690](https://github.com/bnb-chain/bsc/pull/3690)) | +| `--multidatabase` | Removed | Multi-database support is fully removed ([#3716](https://github.com/bnb-chain/bsc/pull/3716)) | +| `--txpool.overflowpoolslots` | Deprecated (no effect) | Overflow pool has been removed ([#3722](https://github.com/bnb-chain/bsc/pull/3722)) | +| `--fake-beacon` | Removed | fake-beacon op-stack shim removed ([#3728](https://github.com/bnb-chain/bsc/pull/3728)) | +| `--fake-beacon.addr` | Removed | See `--fake-beacon` ([#3728](https://github.com/bnb-chain/bsc/pull/3728)) | +| `--fake-beacon.port` | Removed | See `--fake-beacon` ([#3728](https://github.com/bnb-chain/bsc/pull/3728)) | + +**Config File (TOML) Fields** + +| Field | Change | Note | +|---|---|---| +| `[Eth] EnableBAL` | **Removed** — causes load error if present | Remove this field from your config.toml before upgrading ([#3690](https://github.com/bnb-chain/bsc/pull/3690)) | +| `[TxPool] OverflowPoolSlots` | Deprecated — silently ignored | Safe to leave but recommend removing ([#3722](https://github.com/bnb-chain/bsc/pull/3722)) | + +## MetaInfo +Mandatory Update Required: Yes +Target Audience: all BSC Testnet users +Procedure: before upgrading, review the deprecated flags and config fields listed above and confirm their removal has no impact on your node; once confirmed, binary replacement is sufficient: + - `--journalfile`: no longer has any effect, safe to remove + - `--miner.txgaslimit`: per-transaction gas limit is now enforced by EIP-7825; confirm EIP-7825 behaviour meets your requirements before removing + - `--enablebal`: no longer has any effect, safe to remove + - `--multidatabase`: single-database mode is now the only option; confirm your data directory is compatible + - `--txpool.overflowpoolslots`: overflow pool is removed; review your txpool capacity settings if you relied on it + - `[Eth] EnableBAL` in config.toml: **must be removed before upgrading** — will cause a startup error if left in + - `[TxPool] OverflowPoolSlots` in config.toml: silently ignored, but recommend removing to keep config clean +Schedule(Timeline): TBD + ## v1.7.5 v1.7.5 is a maintenance release. diff --git a/beacon/fakebeacon/api_func.go b/beacon/fakebeacon/api_func.go deleted file mode 100644 index 674bf7fb39..0000000000 --- a/beacon/fakebeacon/api_func.go +++ /dev/null @@ -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 -} diff --git a/beacon/fakebeacon/handlers.go b/beacon/fakebeacon/handlers.go deleted file mode 100644 index 53af5aad29..0000000000 --- a/beacon/fakebeacon/handlers.go +++ /dev/null @@ -1,89 +0,0 @@ -package fakebeacon - -import ( - "fmt" - "net/http" - "net/url" - "strconv" - "strings" - - "github.com/prysmaticlabs/prysm/v5/api/server/structs" - "github.com/prysmaticlabs/prysm/v5/network/httputil" -) - -const MaxBlobsPerBlock = 6 - -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, 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 >= MaxBlobsPerBlock { - invalidIndices = append(invalidIndices, raw) - continue - } - for i := range indices { - if ix == indices[i] { - continue loop - } - } - indices = append(indices, ix) - } - - if len(invalidIndices) > 0 { - return nil, fmt.Errorf("requested blob indices %v are invalid", invalidIndices) - } - return indices, nil -} diff --git a/beacon/fakebeacon/server.go b/beacon/fakebeacon/server.go deleted file mode 100644 index ef5cb6af9b..0000000000 --- a/beacon/fakebeacon/server.go +++ /dev/null @@ -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/middleware" -) - -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(middleware.NormalizeQueryValuesHandler) - for _, e := range s.endpoints() { - r.HandleFunc(e.path, e.handler).Methods(e.methods...) - } - return r -} - -type endpoint struct { - path string - handler http.HandlerFunc - methods []string -} - -func (s *Service) endpoints() []endpoint { - return []endpoint{ - { - path: versionMethod, - handler: VersionMethod, - methods: []string{http.MethodGet}, - }, - { - path: specMethod, - handler: SpecMethod, - methods: []string{http.MethodGet}, - }, - { - path: genesisMethod, - handler: GenesisMethod, - methods: []string{http.MethodGet}, - }, - { - path: sidecarsMethodPrefix, - handler: s.SidecarsMethod, - methods: []string{http.MethodGet}, - }, - } -} diff --git a/beacon/fakebeacon/server_test.go b/beacon/fakebeacon/server_test.go deleted file mode 100644 index 0b74f565ba..0000000000 --- a/beacon/fakebeacon/server_test.go +++ /dev/null @@ -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) -} diff --git a/beacon/fakebeacon/utils.go b/beacon/fakebeacon/utils.go deleted file mode 100644 index cc6fe889b9..0000000000 --- a/beacon/fakebeacon/utils.go +++ /dev/null @@ -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) - } - } - } - } -} diff --git a/cmd/geth/chaincmd.go b/cmd/geth/chaincmd.go index 5da9d17ade..d523217913 100644 --- a/cmd/geth/chaincmd.go +++ b/cmd/geth/chaincmd.go @@ -73,11 +73,10 @@ var ( utils.OverrideFermi, utils.OverrideOsaka, utils.OverrideMendel, + utils.OverridePasteur, utils.OverrideBPO1, utils.OverrideBPO2, - utils.OverridePasteur, utils.OverrideVerkle, - // utils.MultiDataBaseFlag, }, utils.DatabaseFlags), Description: ` The init command initializes a new genesis block and definition for the network. @@ -358,6 +357,10 @@ func initGenesis(ctx *cli.Context) error { v := ctx.Uint64(utils.OverrideMendel.Name) overrides.OverrideMendel = &v } + if ctx.IsSet(utils.OverridePasteur.Name) { + v := ctx.Uint64(utils.OverridePasteur.Name) + overrides.OverridePasteur = &v + } if ctx.IsSet(utils.OverrideBPO1.Name) { v := ctx.Uint64(utils.OverrideBPO1.Name) overrides.OverrideBPO1 = &v @@ -366,10 +369,6 @@ func initGenesis(ctx *cli.Context) error { v := ctx.Uint64(utils.OverrideBPO2.Name) overrides.OverrideBPO2 = &v } - if ctx.IsSet(utils.OverridePasteur.Name) { - v := ctx.Uint64(utils.OverridePasteur.Name) - overrides.OverridePasteur = &v - } if ctx.IsSet(utils.OverrideVerkle.Name) { v := ctx.Uint64(utils.OverrideVerkle.Name) overrides.OverrideVerkle = &v @@ -378,17 +377,6 @@ func initGenesis(ctx *cli.Context) error { chaindb := utils.MakeChainDatabase(ctx, stack, false) defer chaindb.Close() - name := "chaindata" - // if the trie data dir has been set, new trie db with a new state database - if ctx.IsSet(utils.MultiDataBaseFlag.Name) { - statediskdb, dbErr := stack.OpenDatabaseWithFreezer(name+"/state", 0, 0, "", "", false) - if dbErr != nil { - utils.Fatalf("Failed to open separate trie database: %v", dbErr) - } - chaindb.SetStateStore(statediskdb) - log.Warn("Multi-database is an experimental feature") - } - triedb := utils.MakeTrieDatabase(ctx, stack, chaindb, ctx.Bool(utils.CachePreimagesFlag.Name), false, genesis.IsVerkle(), false) defer triedb.Close() @@ -399,7 +387,7 @@ func initGenesis(ctx *cli.Context) error { if compatErr != nil { utils.Fatalf("Failed to write chain config: %v", compatErr) } - log.Info("Successfully wrote genesis state", "database", name, "hash", hash.String()) + log.Info("Successfully wrote genesis state", "hash", hash.String()) return nil } @@ -772,12 +760,6 @@ func dumpGenesis(ctx *cli.Context) error { } defer db.Close() - // set the separate state & block database - if stack.CheckIfMultiDataBase() && err == nil { - stateDiskDb := utils.MakeStateDataBase(ctx, stack, true) - db.SetStateStore(stateDiskDb) - } - genesis, err = core.ReadGenesis(db) if err != nil { utils.Fatalf("failed to read genesis: %s", err) @@ -1063,7 +1045,7 @@ func parseDumpConfig(ctx *cli.Context, stack *node.Node, db ethdb.Database) (*st } else { // Use latest if scheme == rawdb.PathScheme { - triedb := triedb.NewDatabase(db, &triedb.Config{PathDB: utils.PathDBConfigAddJournalFilePath(stack, pathdb.ReadOnly)}) + triedb := triedb.NewDatabase(db, &triedb.Config{PathDB: pathdb.ReadOnly}) defer triedb.Close() if stateRoot := triedb.Head(); stateRoot != (common.Hash{}) { header.Root = stateRoot @@ -1136,7 +1118,7 @@ func dumpAllRootHashInPath(ctx *cli.Context) error { defer stack.Close() db := utils.MakeChainDatabase(ctx, stack, true) defer db.Close() - triedb := triedb.NewDatabase(db, &triedb.Config{PathDB: utils.PathDBConfigAddJournalFilePath(stack, pathdb.ReadOnly)}) + triedb := triedb.NewDatabase(db, &triedb.Config{PathDB: pathdb.ReadOnly}) defer triedb.Close() scheme, err := rawdb.ParseStateScheme(ctx.String(utils.StateSchemeFlag.Name), db) diff --git a/cmd/geth/config.go b/cmd/geth/config.go index 6a3d462730..3361a5216e 100644 --- a/cmd/geth/config.go +++ b/cmd/geth/config.go @@ -35,7 +35,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" @@ -102,6 +101,7 @@ var deprecatedConfigFields = map[string]bool{ "ethconfig.Config.LightPeers": true, "ethconfig.Config.LightNoPrune": true, "ethconfig.Config.LightNoSyncServe": true, + "legacypool.Config.OverflowPoolSlots": true, } type ethstatsConfig struct { @@ -109,11 +109,10 @@ type ethstatsConfig struct { } type gethConfig struct { - Eth ethconfig.Config - Node node.Config - Ethstats ethstatsConfig - Metrics metrics.Config - FakeBeacon fakebeacon.Config + Eth ethconfig.Config + Node node.Config + Ethstats ethstatsConfig + Metrics metrics.Config } func loadConfig(file string, cfg *gethConfig) error { @@ -278,6 +277,10 @@ func makeFullNode(ctx *cli.Context) (*node.Node, ethapi.Backend) { v := ctx.Uint64(utils.OverrideMendel.Name) cfg.Eth.OverrideMendel = &v } + if ctx.IsSet(utils.OverridePasteur.Name) { + v := ctx.Uint64(utils.OverridePasteur.Name) + cfg.Eth.OverridePasteur = &v + } if ctx.IsSet(utils.OverrideBPO1.Name) { v := ctx.Uint64(utils.OverrideBPO1.Name) cfg.Eth.OverrideBPO1 = &v @@ -286,10 +289,6 @@ func makeFullNode(ctx *cli.Context) (*node.Node, ethapi.Backend) { v := ctx.Uint64(utils.OverrideBPO2.Name) cfg.Eth.OverrideBPO2 = &v } - if ctx.IsSet(utils.OverridePasteur.Name) { - v := ctx.Uint64(utils.OverridePasteur.Name) - cfg.Eth.OverridePasteur = &v - } if ctx.IsSet(utils.OverrideVerkle.Name) { v := ctx.Uint64(utils.OverrideVerkle.Name) cfg.Eth.OverrideVerkle = &v @@ -355,16 +354,6 @@ func makeFullNode(ctx *cli.Context) (*node.Node, ethapi.Backend) { } } - 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(&cfg.Metrics, utils.EnableBuildInfo(git.Commit, git.Date), diff --git a/cmd/geth/dbcmd.go b/cmd/geth/dbcmd.go index 1bedff0079..09901fac76 100644 --- a/cmd/geth/dbcmd.go +++ b/cmd/geth/dbcmd.go @@ -458,7 +458,7 @@ func inspectTrie(ctx *cli.Context) error { var config *triedb.Config if dbScheme == rawdb.PathScheme { config = &triedb.Config{ - PathDB: utils.PathDBConfigAddJournalFilePath(stack, pathdb.ReadOnly), + PathDB: pathdb.ReadOnly, } } else if dbScheme == rawdb.HashScheme { config = triedb.HashDefaults @@ -550,7 +550,7 @@ func checkStateContent(ctx *cli.Context) error { lastLog = time.Now() ) - it = rawdb.NewKeyLengthIterator(db.GetStateStore().NewIterator(prefix, start), 32) + it = rawdb.NewKeyLengthIterator(db.NewIterator(prefix, start), 32) for it.Next() { count++ k := it.Key() @@ -593,10 +593,6 @@ func dbStats(ctx *cli.Context) error { defer db.Close() showDBStats(db) - if db.HasSeparateStateStore() { - fmt.Println("show stats of state store") - showDBStats(db.GetStateStore()) - } return nil } @@ -611,30 +607,14 @@ func dbCompact(ctx *cli.Context) error { log.Info("Stats before compaction") showDBStats(db) - if stack.CheckIfMultiDataBase() { - fmt.Println("show stats of state store") - showDBStats(db.GetStateStore()) - } - log.Info("Triggering compaction") if err := db.Compact(nil, nil); err != nil { log.Error("Compact err", "error", err) return err } - if stack.CheckIfMultiDataBase() { - if err := db.GetStateStore().Compact(nil, nil); err != nil { - log.Error("Compact err", "error", err) - return err - } - } - log.Info("Stats after compaction") showDBStats(db) - if stack.CheckIfMultiDataBase() { - fmt.Println("show stats of state store after compaction") - showDBStats(db.GetStateStore()) - } return nil } @@ -654,12 +634,7 @@ func dbGet(ctx *cli.Context) error { log.Info("Could not decode the key", "error", err) return err } - opDb := db - if stack.CheckIfMultiDataBase() && rawdb.DataTypeByKey(key) == rawdb.StateDataType { - opDb = db.GetStateStore() - } - - data, err := opDb.Get(key) + data, err := db.Get(key) if err != nil { log.Info("Get operation failed", "key", fmt.Sprintf("%#x", key), "error", err) return err @@ -676,10 +651,8 @@ func dbTrieGet(ctx *cli.Context) error { stack, _ := makeConfigNode(ctx) defer stack.Close() - var db ethdb.Database - chaindb := utils.MakeChainDatabase(ctx, stack, true) - db = chaindb.GetStateStore() - defer chaindb.Close() + db := utils.MakeChainDatabase(ctx, stack, true) + defer db.Close() scheme := ctx.String(utils.StateSchemeFlag.Name) if scheme == "" { @@ -744,10 +717,8 @@ func dbTrieDelete(ctx *cli.Context) error { stack, _ := makeConfigNode(ctx) defer stack.Close() - var db ethdb.Database - chaindb := utils.MakeChainDatabase(ctx, stack, true) - db = chaindb.GetStateStore() - defer chaindb.Close() + db := utils.MakeChainDatabase(ctx, stack, true) + defer db.Close() scheme := ctx.String(utils.StateSchemeFlag.Name) if scheme == "" { @@ -815,16 +786,11 @@ func dbDelete(ctx *cli.Context) error { log.Info("Could not decode the key", "error", err) return err } - opDb := db - if opDb.HasSeparateStateStore() && rawdb.DataTypeByKey(key) == rawdb.StateDataType { - opDb = db.GetStateStore() - } - - data, err := opDb.Get(key) + data, err := db.Get(key) if err == nil { fmt.Printf("Previous value: %#x\n", data) } - if err = opDb.Delete(key); err != nil { + if err = db.Delete(key); err != nil { log.Info("Delete operation returned an error", "key", fmt.Sprintf("%#x", key), "error", err) return err } @@ -843,36 +809,8 @@ func dbDeleteTrieState(ctx *cli.Context) error { db := utils.MakeChainDatabase(ctx, stack, false) defer db.Close() - var ( - err error - start = time.Now() - ) - - // If separate trie db exists, delete all files in the db folder - if db.HasSeparateStateStore() { - statePath := filepath.Join(stack.ResolvePath("chaindata"), "state") - log.Info("Removing separate trie database", "path", statePath) - err = filepath.Walk(statePath, func(path string, info os.FileInfo, err error) error { - if err != nil { - return err - } - if path != statePath { - fileInfo, err := os.Lstat(path) - if err != nil { - return err - } - if !fileInfo.IsDir() { - os.Remove(path) - } - } - return nil - }) - log.Info("Separate trie database deleted", "err", err, "elapsed", common.PrettyDuration(time.Since(start))) - return err - } - // Delete KV pairs from the database - err = rawdb.DeleteTrieState(db) + err := rawdb.DeleteTrieState(db) if err != nil { return err } @@ -891,7 +829,7 @@ func dbDeleteTrieState(ctx *cli.Context) error { } log.Info("Removing ancient state database", "path", dbPath) - start = time.Now() + start := time.Now() filepath.Walk(dbPath, func(path string, info os.FileInfo, err error) error { if dbPath == path { return nil @@ -935,16 +873,11 @@ func dbPut(ctx *cli.Context) error { return err } - opDb := db - if db.HasSeparateStateStore() && rawdb.DataTypeByKey(key) == rawdb.StateDataType { - opDb = db.GetStateStore() - } - - data, err = opDb.Get(key) + data, err = db.Get(key) if err == nil { fmt.Printf("Previous value: %#x\n", data) } - return opDb.Put(key, value) + return db.Put(key, value) } // dbDumpTrie shows the key-value slots of a given storage trie @@ -1035,7 +968,7 @@ func freezerInspect(ctx *cli.Context) error { stack, _ := makeConfigNode(ctx) ancient := stack.ResolveAncient("chaindata", ctx.String(utils.AncientFlag.Name)) stack.Close() - return rawdb.InspectFreezerTable(ancient, freezer, table, start, end, stack.CheckIfMultiDataBase()) + return rawdb.InspectFreezerTable(ancient, freezer, table, start, end) } func importLDBdata(ctx *cli.Context) error { @@ -1307,7 +1240,7 @@ func inspectHistory(ctx *cli.Context) error { if header == nil { return 0, fmt.Errorf("block #%d is not existent", blockNumber) } - id := rawdb.ReadStateID(db.GetStateStore(), header.Root) + id := rawdb.ReadStateID(db, header.Root) if id == nil { first, last, err := triedb.HistoryRange() if err == nil { diff --git a/cmd/geth/main.go b/cmd/geth/main.go index 1e13ea9f9b..9834460db2 100644 --- a/cmd/geth/main.go +++ b/cmd/geth/main.go @@ -26,8 +26,6 @@ import ( "strings" "time" - "github.com/ethereum/go-ethereum/params" - "github.com/ethereum/go-ethereum/accounts" "github.com/ethereum/go-ethereum/accounts/keystore" "github.com/ethereum/go-ethereum/cmd/utils" @@ -78,9 +76,9 @@ var ( utils.OverrideFermi, utils.OverrideOsaka, utils.OverrideMendel, + utils.OverridePasteur, utils.OverrideBPO1, utils.OverrideBPO2, - utils.OverridePasteur, utils.OverrideVerkle, utils.OverrideGenesisFlag, utils.OverrideFullImmutabilityThreshold, @@ -99,10 +97,11 @@ var ( utils.TxPoolGlobalSlotsFlag, utils.TxPoolAccountQueueFlag, utils.TxPoolGlobalQueueFlag, - utils.TxPoolOverflowPoolSlotsFlag, + utils.TxPoolOverflowPoolSlotsFlag, // deprecated utils.TxPoolLifetimeFlag, utils.TxPoolReannounceTimeFlag, utils.MinerTxGasLimitFlag, + utils.EnableBALFlag, utils.BlobPoolDataDirFlag, utils.BlobPoolDataCapFlag, utils.BlobPoolPriceBumpFlag, @@ -121,7 +120,7 @@ var ( utils.LogExportCheckpointsFlag, utils.StateHistoryFlag, utils.PathDBSyncFlag, - utils.JournalFileFlag, + utils.JournalFileFlag, // deprecated utils.LightKDFFlag, utils.EthRequiredBlocksFlag, utils.LegacyWhitelistFlag, // deprecated @@ -135,7 +134,6 @@ var ( utils.CacheSnapshotFlag, // utils.CacheNoPrefetchFlag, utils.CachePreimagesFlag, - // utils.MultiDataBaseFlag, utils.PruneAncientDataFlag, // deprecated utils.CacheLogSizeFlag, utils.FDLimitFlag, @@ -153,7 +151,6 @@ var ( utils.MinerRecommitIntervalFlag, utils.MinerNewPayloadTimeoutFlag, // deprecated utils.MinerDelayLeftoverFlag, - utils.EnableBALFlag, // utils.MinerNewPayloadTimeout, utils.NATFlag, utils.NoDiscoverFlag, @@ -262,12 +259,6 @@ var ( utils.MetricsInfluxDBOrganizationFlag, utils.StateSizeTrackingFlag, } - - fakeBeaconFlags = []cli.Flag{ - utils.FakeBeaconEnabledFlag, - utils.FakeBeaconAddrFlag, - utils.FakeBeaconPortFlag, - } ) var app = flags.NewApp("the go-ethereum command line interface") @@ -324,7 +315,6 @@ func init() { consoleFlags, debug.Flags, metricsFlags, - fakeBeaconFlags, ) flags.AutoEnvVars(app.Flags, "GETH") @@ -465,20 +455,6 @@ 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() - maxTxGas := uint64(0) - if gasCeil > params.SystemTxsGasSoftLimit { - maxTxGas = gasCeil - params.SystemTxsGasSoftLimit - } - if txGasLimit := ethBackend.Miner().TxGasLimit(); txGasLimit > 0 { - if maxTxGas == 0 || txGasLimit < maxTxGas { - maxTxGas = txGasLimit - } - } - if maxTxGas > 0 { - ethBackend.TxPool().SetMaxGas(maxTxGas) - } - if ctx.Bool(utils.MiningEnabledFlag.Name) { // Mining only makes sense if a full Ethereum node is running if ctx.String(utils.SyncModeFlag.Name) == "light" { diff --git a/cmd/jsutils/getchainstatus.js b/cmd/jsutils/getchainstatus.js index b74864047c..c00e704354 100644 --- a/cmd/jsutils/getchainstatus.js +++ b/cmd/jsutils/getchainstatus.js @@ -290,6 +290,58 @@ const builderMap = new Map([ ["0xA8caEc0D68a90Ac971EA1aDEFA1747447e1f9871", "blockroute"], ]); +function getMappedAddressName(addressMap, address) { + if (!address) return undefined; + try { + const normalized = ethers.getAddress(address); + return addressMap.get(normalized) || addressMap.get(normalized.toLowerCase()); + } catch (_) { + return addressMap.get(address); + } +} + +async function getBlockMevInfo(blockNumber) { + let rpcInfo; + try { + rpcInfo = await provider.send("eth_getBlockMevInfo", ["0x" + blockNumber.toString(16)]); + if (rpcInfo) { + if (!rpcInfo.builder) { + return { ...rpcInfo, source: "local" }; + } + const source = rpcInfo.version === "v2" ? "bidblock" : "bid"; + return { ...rpcInfo, source }; + } + } catch (_) { + // Older validators do not expose eth_getBlockMevInfo; fall back to the + // pre-BEP-675 payment-tx heuristic below. + } + + const block = await provider.getBlock(blockNumber); + if (!block) return rpcInfo || { blockNumber, source: "local" }; + + const txHashes = block.transactions.slice(-4); + const txResults = await Promise.all(txHashes.map(txHash => provider.getTransaction(txHash))); + for (const txData of txResults) { + if (!txData || !txData.to || !getMappedAddressName(builderMap, txData.to)) continue; + return { + blockNumber: block.number, + blockHash: block.hash, + miner: block.miner, + source: "bid", + builder: txData.to, + fallback: true, + }; + } + + return { + ...(rpcInfo || {}), + blockNumber: rpcInfo ? (rpcInfo.blockNumber || block.number) : block.number, + blockHash: rpcInfo ? (rpcInfo.blockHash || block.hash) : block.hash, + miner: rpcInfo ? (rpcInfo.miner || block.miner) : block.miner, + source: "local", + }; +} + // 1.cmd: "GetMaxTxCountInBlockRange", usage: // node getchainstatus.js GetMaxTxCountInBlockRange --rpc https://bsc-testnet-dataseed.bnbchain.org \ // --startNum 40000001 --endNum 40000005 \ @@ -856,6 +908,8 @@ async function getMevStatus() { local: 0, ...Object.fromEntries([...new Set(builderMap.values())].map(builder => [builder, 0])) }; + // Per-type tallies for the MEV path breakdown (v1 = legacy SendBid, v2 = bidblock). + let typeCounts = { mev_v1: 0, mev_v2: 0, local: 0 }; // Get the latest block number const latestBlock = await provider.getBlockNumber(); @@ -877,12 +931,18 @@ async function getMevStatus() { return; } - const blockPromises = []; + const blockNumbers = []; for (let i = startBlock; i <= endBlock; i++) { - blockPromises.push(provider.getBlock(i)); + blockNumbers.push(i); } - const blocks = await Promise.all(blockPromises); + let mevInfos; + try { + mevInfos = await Promise.all(blockNumbers.map(getBlockMevInfo)); + } catch (err) { + console.error("GetMevStatus failed:", err.shortMessage || err.message || err); + return; + } // Calculate max lengths for alignment with default values let maxMinerLength = 10; // Default length @@ -898,38 +958,39 @@ async function getMevStatus() { maxBuilderLength = Math.max(...builderLengths); } - for (const blockData of blocks) { - const minerInfo = validatorMap.get(blockData.miner); + for (const mevInfo of mevInfos) { + const blockNumber = typeof mevInfo.blockNumber === "string" + ? BigInt(mevInfo.blockNumber).toString() + : mevInfo.blockNumber.toString(); + const minerInfo = getMappedAddressName(validatorMap, mevInfo.miner); const miner = minerInfo ? minerInfo[0] : "Unknown"; - const transactions = blockData.transactions.slice(-4); // Last 4 transactions - const txPromises = transactions.map(txHash => provider.getTransaction(txHash)); - - const txResults = await Promise.all(txPromises); - let mevBlock = false; - - for (const txData of txResults) { - if (builderMap.has(txData.to)) { - const builder = builderMap.get(txData.to); - counts[builder]++; - - mevBlock = true; - console.log( - `blockNum: ${blockData.number.toString().padStart(8)} ` + - `miner: ${miner.padEnd(maxMinerLength)} ` + - `builder: (${builder.padEnd(maxBuilderLength)}) ${txData.to}` - ); - break; - } - } - if (!mevBlock) { - counts.local++; + if (mevInfo.source !== "local") { + const builderName = getMappedAddressName(builderMap, mevInfo.builder); + const friendlyName = builderName || mevInfo.builder; + const bucket = builderName || mevInfo.builder; + // v2 = bidblock (tagged), everything else on the MEV path = v1 + // (tagged legacy bid, or heuristic-detected payBidTx which is v1-only). + const typeLabel = (mevInfo.source === "bidblock" || mevInfo.version === "v2") ? "mev_v2" : "mev_v1"; + counts[bucket] = (counts[bucket] || 0) + 1; + typeCounts[typeLabel]++; console.log( - `blockNum: ${blockData.number.toString().padStart(8)} ` + + `blockNum: ${blockNumber.padStart(8)} ` + + `type: ${typeLabel.padEnd(6)} ` + `miner: ${miner.padEnd(maxMinerLength)} ` + - `builder: local` + `builder: (${friendlyName.padEnd(maxBuilderLength)}) ${mevInfo.builder}` ); + continue; } + + counts.local++; + typeCounts.local++; + console.log( + `blockNum: ${blockNumber.padStart(8)} ` + + `type: ${"local".padEnd(6)} ` + + `miner: ${miner.padEnd(maxMinerLength)} ` + + `builder: local` + ); } const total = endBlock - startBlock + 1; @@ -947,6 +1008,17 @@ async function getMevStatus() { const ratio = (value * 100 / total).toFixed(2); console.log(`${key.padEnd(maxBuilderLength)}: ${value.toString().padStart(3)} blocks (${ratio}%)`); }); + + // MEV path breakdown: v1 (legacy SendBid) vs v2 (bidblock), as a share of MEV blocks. + const mevTotal = typeCounts.mev_v1 + typeCounts.mev_v2; + console.log("\nMEV Path Distribution:"); + console.log(`MEV blocks: ${mevTotal} (${(mevTotal * 100 / total).toFixed(2)}% of total)`); + if (mevTotal > 0) { + const v1Ratio = (typeCounts.mev_v1 * 100 / mevTotal).toFixed(2); + const v2Ratio = (typeCounts.mev_v2 * 100 / mevTotal).toFixed(2); + console.log(`${"mev_v1".padEnd(8)}: ${typeCounts.mev_v1.toString().padStart(3)} blocks (${v1Ratio}% of MEV)`); + console.log(`${"mev_v2".padEnd(8)}: ${typeCounts.mev_v2.toString().padStart(3)} blocks (${v2Ratio}% of MEV)`); + } } // 11.cmd: "getLargeTxs", usage: diff --git a/cmd/utils/flags.go b/cmd/utils/flags.go index b75d6a813f..be4cd15962 100644 --- a/cmd/utils/flags.go +++ b/cmd/utils/flags.go @@ -37,7 +37,6 @@ import ( "github.com/ethereum/go-ethereum/accounts" "github.com/ethereum/go-ethereum/accounts/keystore" - "github.com/ethereum/go-ethereum/beacon/fakebeacon" bparams "github.com/ethereum/go-ethereum/beacon/params" "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/common/fdlimit" @@ -97,12 +96,6 @@ var ( Value: flags.DirectoryString(node.DefaultDataDir()), Category: flags.EthCategory, } - MultiDataBaseFlag = &cli.BoolFlag{ - Name: "multidatabase", - Usage: "Enable a separated state database, it will be created subdirectory called state, " + - "Users can copy this state directory to another directory or disk, and then create a symbolic link to the state directory under the chaindata", - Category: flags.EthCategory, - } DirectBroadcastFlag = &cli.BoolFlag{ Name: "directbroadcast", Usage: "Enable directly broadcast mined block to all peers", @@ -182,11 +175,6 @@ var ( Usage: "Chapel network: pre-configured Proof-of-Stake-Authority BSC test network", Category: flags.EthCategory, } - EnableBALFlag = &cli.BoolFlag{ - Name: "enablebal", - Usage: "Enable block access list feature, validator will generate BAL for each block", - Category: flags.EthCategory, - } // Dev mode DeveloperFlag = &cli.BoolFlag{ Name: "dev", @@ -324,6 +312,11 @@ var ( Usage: "Manually specify the Mendel fork timestamp, overriding the bundled setting", Category: flags.EthCategory, } + OverridePasteur = &cli.Uint64Flag{ + Name: "override.pasteur", + Usage: "Manually specify the Pasteur fork timestamp, overriding the bundled setting", + Category: flags.EthCategory, + } OverrideBPO1 = &cli.Uint64Flag{ Name: "override.bpo1", Usage: "Manually specify the bpo1 fork timestamp, overriding the bundled setting", @@ -334,11 +327,6 @@ var ( Usage: "Manually specify the bpo2 fork timestamp, overriding the bundled setting", Category: flags.EthCategory, } - OverridePasteur = &cli.Uint64Flag{ - Name: "override.pasteur", - Usage: "Manually specify the Pasteur fork timestamp, overriding the bundled setting", - Category: flags.EthCategory, - } OverrideVerkle = &cli.Uint64Flag{ Name: "override.verkle", Usage: "Manually specify the Verkle fork timestamp, overriding the bundled setting", @@ -566,12 +554,6 @@ var ( Value: ethconfig.Defaults.TxPool.GlobalQueue, Category: flags.TxPoolCategory, } - TxPoolOverflowPoolSlotsFlag = &cli.Uint64Flag{ - Name: "txpool.overflowpoolslots", - Usage: "Maximum number of transaction slots in overflow pool", - Value: ethconfig.Defaults.TxPool.OverflowPoolSlots, - Category: flags.TxPoolCategory, - } TxPoolLifetimeFlag = &cli.DurationFlag{ Name: "txpool.lifetime", Usage: "Maximum amount of time non-executable transaction are queued", @@ -584,11 +566,6 @@ var ( Value: ethconfig.Defaults.TxPool.ReannounceTime, Category: flags.TxPoolCategory, } - MinerTxGasLimitFlag = &cli.Uint64Flag{ - Name: "miner.txgaslimit", - Usage: fmt.Sprintf("Maximum gas allowed per transaction (default = 0, disabled; min = %d)", params.MaxTxGas), - Category: flags.MinerCategory, - } // Blob transaction pool settings BlobPoolDataDirFlag = &cli.StringFlag{ Name: "blobpool.datadir", @@ -1326,25 +1303,6 @@ 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, - } - FakeBeaconAddrFlag = &cli.StringFlag{ - Name: "fake-beacon.addr", - Usage: "HTTP-RPC server listening addr of fake-beacon", - Value: fakebeacon.DefaultAddr, - Category: flags.APICategory, - } - FakeBeaconPortFlag = &cli.IntFlag{ - Name: "fake-beacon.port", - Usage: "HTTP-RPC server listening port of fake-beacon", - Value: fakebeacon.DefaultPort, - Category: flags.APICategory, - } - // incremental snapshot related flags EnableIncrSnapshotFlag = &cli.BoolFlag{ Name: "incr.enable", @@ -1862,9 +1820,6 @@ func SetNodeConfig(ctx *cli.Context, cfg *node.Config) { if ctx.IsSet(DisableSnapProtocolFlag.Name) { cfg.DisableSnapProtocol = ctx.Bool(DisableSnapProtocolFlag.Name) } - if ctx.IsSet(EnableBALFlag.Name) { - cfg.EnableBAL = ctx.Bool(EnableBALFlag.Name) - } if ctx.IsSet(RangeLimitFlag.Name) { cfg.RangeLimit = ctx.Bool(RangeLimitFlag.Name) } @@ -1992,7 +1947,7 @@ func setTxPool(ctx *cli.Context, cfg *legacypool.Config) { cfg.GlobalQueue = ctx.Uint64(TxPoolGlobalQueueFlag.Name) } if ctx.IsSet(TxPoolOverflowPoolSlotsFlag.Name) { - cfg.OverflowPoolSlots = ctx.Uint64(TxPoolOverflowPoolSlotsFlag.Name) + log.Warn("The flag --txpool.overflowpoolslots is deprecated and has no effect") } if ctx.IsSet(TxPoolLifetimeFlag.Name) { cfg.Lifetime = ctx.Duration(TxPoolLifetimeFlag.Name) @@ -2044,11 +1999,7 @@ func setMiner(ctx *cli.Context, cfg *minerconfig.Config) { cfg.DisableVoteAttestation = true } if ctx.IsSet(MinerTxGasLimitFlag.Name) { - limit := ctx.Uint64(MinerTxGasLimitFlag.Name) - if limit != 0 && limit < params.MaxTxGas { - Fatalf("Invalid --miner.txgaslimit: %d (must be >= %d or 0)", limit, params.MaxTxGas) - } - cfg.TxGasLimit = limit + log.Warn("The flag --miner.txgaslimit is deprecated and has no effect; per-transaction gas limit is now enforced by EIP-7825") } } @@ -2086,6 +2037,9 @@ func SetEthConfig(ctx *cli.Context, stack *node.Node, cfg *ethconfig.Config) { flags.CheckExclusive(ctx, BSCMainnetFlag, DeveloperFlag, NetworkIdFlag, OverrideGenesisFlag) flags.CheckExclusive(ctx, DeveloperFlag, ExternalSignerFlag) // Can't use both ephemeral unlocked and external signer + if ctx.IsSet(EnableBALFlag.Name) { + log.Warn("The flag --enable-bal is deprecated and has no effect; BEP-592 block access list has been removed") + } // Set configurations from CLI flags setEtherbase(ctx, cfg) setGPO(ctx, &cfg.GPO) @@ -2171,9 +2125,6 @@ func SetEthConfig(ctx *cli.Context, stack *node.Node, cfg *ethconfig.Config) { if ctx.IsSet(CacheNoPrefetchFlag.Name) { cfg.NoPrefetch = ctx.Bool(CacheNoPrefetchFlag.Name) } - if ctx.IsSet(EnableBALFlag.Name) { - cfg.EnableBAL = ctx.Bool(EnableBALFlag.Name) - } // Read the value from the flag no matter if it's set or not. cfg.Preimages = ctx.Bool(CachePreimagesFlag.Name) if cfg.NoPruning && !cfg.Preimages { @@ -2597,17 +2548,16 @@ func EnableNodeInfo(poolConfig *legacypool.Config, nodeInfo *p2p.NodeInfo) Setup return func() { // register node info into metrics metrics.GetOrRegisterLabel("node-info", nil).Mark(map[string]interface{}{ - "Enode": nodeInfo.Enode, - "ENR": nodeInfo.ENR, - "ID": nodeInfo.ID, - "PriceLimit": poolConfig.PriceLimit, - "PriceBump": poolConfig.PriceBump, - "AccountSlots": poolConfig.AccountSlots, - "GlobalSlots": poolConfig.GlobalSlots, - "AccountQueue": poolConfig.AccountQueue, - "GlobalQueue": poolConfig.GlobalQueue, - "OverflowPoolSlots": poolConfig.OverflowPoolSlots, - "Lifetime": poolConfig.Lifetime, + "Enode": nodeInfo.Enode, + "ENR": nodeInfo.ENR, + "ID": nodeInfo.ID, + "PriceLimit": poolConfig.PriceLimit, + "PriceBump": poolConfig.PriceBump, + "AccountSlots": poolConfig.AccountSlots, + "GlobalSlots": poolConfig.GlobalSlots, + "AccountQueue": poolConfig.AccountQueue, + "GlobalQueue": poolConfig.GlobalQueue, + "Lifetime": poolConfig.Lifetime, }) } } @@ -2655,9 +2605,6 @@ func parseDBFeatures(cfg *ethconfig.Config, stack *node.Node) string { } else if cfg.StateScheme == rawdb.HashScheme { features = append(features, "HBSS") } - if stack.CheckIfMultiDataBase() { - features = append(features, "MultiDB") - } if cfg.PruneAncientData || cfg.BlockHistory > 0 { features = append(features, "PruneBlocks") } @@ -2784,11 +2731,6 @@ func MakeChainDatabase(ctx *cli.Context, stack *node.Node, readonly bool) ethdb. EraDirectory: ctx.String(EraFlag.Name), } chainDb, err = stack.OpenDatabaseWithOptions("chaindata", options) - // set the separate state database - if stack.CheckIfMultiDataBase() && err == nil { - stateDiskDb := MakeStateDataBase(ctx, stack, readonly) - chainDb.SetStateStore(stateDiskDb) - } } if err != nil { Fatalf("Could not open database: %v", err) @@ -2796,23 +2738,6 @@ func MakeChainDatabase(ctx *cli.Context, stack *node.Node, readonly bool) ethdb. return chainDb } -// MakeStateDataBase open a separate state database using the flags passed to the client and will hard crash if it fails. -func MakeStateDataBase(ctx *cli.Context, stack *node.Node, readonly bool) ethdb.Database { - cache := ctx.Int(CacheFlag.Name) * ctx.Int(CacheDatabaseFlag.Name) / 100 - handles := MakeDatabaseHandles(ctx.Int(FDLimitFlag.Name)) * 90 / 100 - statediskdb, err := stack.OpenDatabaseWithFreezer("chaindata/state", cache, handles, "", "", readonly) - if err != nil { - Fatalf("Failed to open separate trie database: %v", err) - } - return statediskdb -} - -func PathDBConfigAddJournalFilePath(stack *node.Node, config *pathdb.Config) *pathdb.Config { - path := fmt.Sprintf("%s/%s", stack.ResolvePath("chaindata"), eth.JournalFileName) - config.JournalFilePath = path - return config -} - // tryMakeReadOnlyDatabase try to open the chain database in read-only mode, // or fallback to write mode if the database is not initialized. // @@ -2898,7 +2823,6 @@ func MakeChain(ctx *cli.Context, stack *node.Node, readonly bool) (*core.BlockCh options := &core.BlockChainConfig{ TrieCleanLimit: ethconfig.Defaults.TrieCleanCache, NoPrefetch: ctx.Bool(CacheNoPrefetchFlag.Name), - EnableBAL: ctx.Bool(EnableBALFlag.Name), TrieDirtyLimit: ethconfig.Defaults.TrieDirtyCache, ArchiveMode: ctx.String(GCModeFlag.Name) == "archive", TrieTimeLimit: ethconfig.Defaults.TrieTimeout, @@ -2944,8 +2868,6 @@ func MakeChain(ctx *cli.Context, stack *node.Node, readonly bool) (*core.BlockCh } vmcfg := vm.Config{ EnablePreimageRecording: ctx.Bool(VMEnableDebugFlag.Name), - EnableWitnessStats: ctx.Bool(VMWitnessStatsFlag.Name), - StatelessSelfValidation: ctx.Bool(VMStatelessSelfValidationFlag.Name) || ctx.Bool(VMWitnessStatsFlag.Name), EnableOpcodeOptimizations: ctx.Bool(VMOpcodeOptimizeFlag.Name), } @@ -2964,6 +2886,9 @@ func MakeChain(ctx *cli.Context, stack *node.Node, readonly bool) (*core.BlockCh } options.VmConfig = vmcfg + options.StatelessSelfValidation = ctx.Bool(VMStatelessSelfValidationFlag.Name) || ctx.Bool(VMWitnessStatsFlag.Name) + options.EnableWitnessStats = ctx.Bool(VMWitnessStatsFlag.Name) + chain, err := core.NewBlockChain(chainDb, gspec, engine, options) if err != nil { Fatalf("Can't create BlockChain: %v", err) @@ -2990,6 +2915,9 @@ func MakeConsolePreloads(ctx *cli.Context) []string { // MakeTrieDatabase constructs a trie database based on the configured scheme. func MakeTrieDatabase(ctx *cli.Context, stack *node.Node, disk ethdb.Database, preimage bool, readOnly bool, isVerkle bool, mergeIncr bool) *triedb.Database { + if ctx.IsSet(JournalFileFlag.Name) { + log.Warn("--journalfile is deprecated and has no effect, please remove it") + } config := &triedb.Config{ Preimages: preimage, IsVerkle: isVerkle, @@ -3016,7 +2944,6 @@ func MakeTrieDatabase(ctx *cli.Context, stack *node.Node, disk ethdb.Database, p } pathConfig.JournalDirectory = stack.ResolvePath("triedb") config.PathDB = &pathConfig - config.PathDB.JournalFilePath = fmt.Sprintf("%s/%s", stack.ResolvePath("chaindata"), eth.JournalFileName) return triedb.NewDatabase(disk, config) } diff --git a/cmd/utils/flags_legacy.go b/cmd/utils/flags_legacy.go index 1ac54c5742..f07e6979a4 100644 --- a/cmd/utils/flags_legacy.go +++ b/cmd/utils/flags_legacy.go @@ -47,6 +47,8 @@ var DeprecatedFlags = []cli.Flag{ PruneAncientDataFlag, JournalFileFlag, LogExportCheckpointsFlag, + EnableBALFlag, + TxPoolOverflowPoolSlotsFlag, } var ( @@ -140,6 +142,27 @@ var ( Value: true, Category: flags.DeprecatedCategory, } + // Deprecated: tx gas limit is now enforced at protocol level by EIP-7825. + MinerTxGasLimitFlag = &cli.Uint64Flag{ + Name: "miner.txgaslimit", + Hidden: true, + Usage: "Deprecated: per-transaction gas limit is now enforced by EIP-7825; this flag has no effect", + Category: flags.DeprecatedCategory, + } + // Deprecated: BEP-592 non-consensus BAL is superseded by EIP-7928 in upstream go-ethereum. + EnableBALFlag = &cli.BoolFlag{ + Name: "enable-bal", + Hidden: true, + Usage: "Deprecated: BEP-592 block access list has been removed; this flag has no effect", + Category: flags.DeprecatedCategory, + } + TxPoolOverflowPoolSlotsFlag = &cli.Uint64Flag{ + Name: "txpool.overflowpoolslots", + Hidden: true, + Usage: "Deprecated: Maximum number of transaction slots in overflow pool; this flag has no effect", + Value: 0, + Category: flags.DeprecatedCategory, + } ) // showDeprecated displays deprecated flags that will be soon removed from the codebase. diff --git a/consensus/beacon/consensus.go b/consensus/beacon/consensus.go index 9d631beb70..200459b301 100644 --- a/consensus/beacon/consensus.go +++ b/consensus/beacon/consensus.go @@ -468,15 +468,6 @@ func (beacon *Beacon) SealHash(header *types.Header) common.Hash { return beacon.ethone.SealHash(header) } -func (beacon *Beacon) SignBAL(blockAccessList *types.BlockAccessListEncode) error { - return nil -} - -// VerifyBAL verifies the BAL of the block -func (beacon *Beacon) VerifyBAL(block *types.Block, bal *types.BlockAccessListEncode) error { - return nil -} - // CalcDifficulty is the difficulty adjustment algorithm. It returns // the difficulty that a new block should have when created at time // given the parent block's time and difficulty. diff --git a/consensus/clique/clique.go b/consensus/clique/clique.go index 411ddc5fd4..7e5e85c578 100644 --- a/consensus/clique/clique.go +++ b/consensus/clique/clique.go @@ -787,11 +787,3 @@ func encodeSigHeader(w io.Writer, header *types.Header) { panic("can't encode: " + err.Error()) } } - -func (c *Clique) SignBAL(bal *types.BlockAccessListEncode) error { - return nil -} - -func (c *Clique) VerifyBAL(block *types.Block, bal *types.BlockAccessListEncode) error { - return nil -} diff --git a/consensus/consensus.go b/consensus/consensus.go index f90f708a55..63a5719f5d 100644 --- a/consensus/consensus.go +++ b/consensus/consensus.go @@ -133,12 +133,6 @@ type Engine interface { // SealHash returns the hash of a block prior to it being sealed. SealHash(header *types.Header) common.Hash - // SignBAL signs the BAL of the block - SignBAL(blockAccessList *types.BlockAccessListEncode) error - - // VerifyBAL verifies the BAL of the block - VerifyBAL(block *types.Block, bal *types.BlockAccessListEncode) error - // CalcDifficulty is the difficulty adjustment algorithm. It returns the difficulty // that a new block should have. CalcDifficulty(chain ChainHeaderReader, time uint64, parent *types.Header) *big.Int diff --git a/consensus/ethash/ethash.go b/consensus/ethash/ethash.go index 3027898981..f624f73875 100644 --- a/consensus/ethash/ethash.go +++ b/consensus/ethash/ethash.go @@ -76,11 +76,3 @@ func (ethash *Ethash) Close() error { func (ethash *Ethash) Seal(chain consensus.ChainHeaderReader, block *types.Block, results chan<- *types.Block, stop <-chan struct{}) error { panic("ethash (pow) sealing not supported any more") } - -func (ethash *Ethash) SignBAL(bal *types.BlockAccessListEncode) error { - return nil -} - -func (ethash *Ethash) VerifyBAL(block *types.Block, bal *types.BlockAccessListEncode) error { - return nil -} diff --git a/consensus/parlia/bid_block.go b/consensus/parlia/bid_block.go new file mode 100644 index 0000000000..a224c8cac7 --- /dev/null +++ b/consensus/parlia/bid_block.go @@ -0,0 +1,225 @@ +package parlia + +import ( + "bytes" + "errors" + "fmt" + "math/big" + + "github.com/ethereum/go-ethereum/accounts" + "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/consensus" + "github.com/ethereum/go-ethereum/core/state" + "github.com/ethereum/go-ethereum/core/systemcontracts" + "github.com/ethereum/go-ethereum/core/tracing" + "github.com/ethereum/go-ethereum/core/types" + buildertypes "github.com/ethereum/go-ethereum/core/types/builder" +) + +var signableSystemTxSelectors = map[string][4]byte{ + "deposit": {0xf3, 0x40, 0xfa, 0x01}, + "distributeFinalityReward": {0x30, 0x0c, 0x35, 0x67}, + "updateValidatorSetV2": {0x1e, 0x4c, 0x15, 0x24}, +} + +type expectedSystemTxEntry struct { + method string + selector [4]byte +} + +// PrepareForBidBlock is Prepare with Coinbase set to the in-turn validator instead of p.val. +func (p *Parlia) PrepareForBidBlock(chain consensus.ChainHeaderReader, header *types.Header) error { + // Coinbase must be set before prepare(): backOffTime and calcDifficulty depend on it. + number := header.Number.Uint64() + snap, err := p.snapshot(chain, number-1, header.ParentHash, nil) + if err != nil { + return err + } + header.Coinbase = snap.inturnValidator() + return p.prepare(chain, header) +} + +// FinalizeAndAssembleBidBlock assembles a BidBlock with unsigned system txs. +func (p *Parlia) FinalizeAndAssembleBidBlock(chain consensus.ChainHeaderReader, header *types.Header, state *state.StateDB, + body *types.Body, receipts []*types.Receipt, tracer *tracing.Hooks) (*types.Block, []*types.Receipt, error) { + block, receipts, err := p.finalizeAndAssemble(chain, header, state, body, receipts, tracer, systemTxPacking) + if err != nil { + return nil, nil, err + } + return block, receipts, nil +} + +// SignSystemTx signs a BidBlock system tx with the validator key. +func (p *Parlia) SignSystemTx(tx *types.Transaction, chainID *big.Int) (*types.Transaction, error) { + p.lock.RLock() + defer p.lock.RUnlock() + if p.signTxFn == nil { + return nil, errors.New("signTxFn not set") + } + return p.signTxFn(accounts.Account{Address: p.val}, tx, chainID) +} + +// isUnsignedSystemTxCandidate reports whether tx looks like an unsigned +// BidBlock system tx. It does not recover the sender. +func (p *Parlia) isUnsignedSystemTxCandidate(tx *types.Transaction) bool { + if tx == nil || tx.To() == nil || !isToSystemContract(*tx.To()) { + return false + } + if tx.GasPrice() == nil || tx.EffectiveGasPriceForBSC().Sign() != 0 { + return false + } + v, r, s := tx.RawSignatureValues() + return isZeroSig(v, r, s) +} + +// isSignableSystemTx reports whether tx can be bind-signed for BidBlock. +func (p *Parlia) isSignableSystemTx(tx *types.Transaction) bool { + if !p.isUnsignedSystemTxCandidate(tx) { + return false + } + if *tx.To() != common.HexToAddress(systemcontracts.ValidatorContract) { + return false + } + return p.hasSignableSelector(tx.Data()) +} + +// expectedSystemTxShape returns the expected trailing system-tx order for accepted BidBlocks: +// +// deposit -> distributeFinalityReward (cond.) -> updateValidatorSetV2 (cond.) +// +// Precondition: BidBlock admission has already enforced a non-zero deposit value. +func (p *Parlia) expectedSystemTxShape(header, parent *types.Header) []expectedSystemTxEntry { + shape := make([]expectedSystemTxEntry, 0, 3) + + shape = append(shape, expectedSystemTxEntry{ + method: "deposit", + selector: p.selectorFor("deposit"), + }) + + if header.Number.Uint64()%finalityRewardInterval == 0 { + shape = append(shape, expectedSystemTxEntry{ + method: "distributeFinalityReward", + selector: p.selectorFor("distributeFinalityReward"), + }) + } + + if isBreatheBlock(parent.Time, header.Time) { + shape = append(shape, expectedSystemTxEntry{ + method: "updateValidatorSetV2", + selector: p.selectorFor("updateValidatorSetV2"), + }) + } + + return shape +} + +func (p *Parlia) verifySystemTxShape(txs []*types.Transaction, shape []expectedSystemTxEntry) error { + if len(txs) < len(shape) { + return fmt.Errorf("missing required system tx %q", shape[len(txs)].method) + } + if len(txs) > len(shape) { + return fmt.Errorf("unexpected extra system tx at position %d (selector 0x%x)", + len(shape), txSelector(txs[len(shape)])) + } + for i, exp := range shape { + if !bytes.HasPrefix(txs[i].Data(), exp.selector[:]) { + return fmt.Errorf("expected system tx %q at position %d, got selector 0x%x", + exp.method, i, txSelector(txs[i])) + } + } + return nil +} + +// ExtractBidBlockDepositValue locates the trailing unsigned system-tx region and +// returns its start index along with the value of the deposit tx (zero if absent). +func (p *Parlia) ExtractBidBlockDepositValue(txs []*types.Transaction) (int, *big.Int) { + systemTxStart := len(txs) + for i := len(txs) - 1; i >= 0; i-- { + if !p.isUnsignedSystemTxCandidate(txs[i]) { + break + } + systemTxStart = i + } + // Deposit is the first trailing unsigned system tx (see expectedSystemTxShape). + // systemTxStart == 0 means there are no preceding user txs to collect fees from, + // which is invalid by design — return zero GasFee so admission rejects it. + if systemTxStart > 0 && systemTxStart < len(txs) { + depositSel := p.selectorFor("deposit") + if bytes.HasPrefix(txs[systemTxStart].Data(), depositSel[:]) { + return systemTxStart, new(big.Int).Set(txs[systemTxStart].Value()) + } + } + return systemTxStart, new(big.Int) +} + +// VerifyBidBlockSystemTxs validates the trailing unsigned system-tx region starting at systemTxStart. +// +// Stage 1 — each trailing unsigned tx must be on the BEP-675 signable whitelist. +// Stage 2 — selectors & order must match expectedSystemTxShape for this header. +func (p *Parlia) VerifyBidBlockSystemTxs(decoded *buildertypes.DecodedBidBlock, parent *types.Header, systemTxStart int) error { + for i := systemTxStart; i < len(decoded.Txs); i++ { + if !p.isSignableSystemTx(decoded.Txs[i]) { + toAddr := "" + if decoded.Txs[i].To() != nil { + toAddr = decoded.Txs[i].To().Hex() + } + return fmt.Errorf("unsigned system tx at position %d (to=%s) is not on the signable whitelist", i, toAddr) + } + } + shape := p.expectedSystemTxShape(decoded.Header, parent) + return p.verifySystemTxShape(decoded.Txs[systemTxStart:], shape) +} + +func (p *Parlia) hasSignableSelector(data []byte) bool { + if len(data) < 4 { + return false + } + selector := data[:4] + for _, methodSelector := range signableSystemTxSelectors { + if bytes.Equal(selector, methodSelector[:]) { + return true + } + } + return false +} + +func (p *Parlia) selectorFor(methodName string) [4]byte { + selector, ok := signableSystemTxSelectors[methodName] + if !ok { + panic(fmt.Sprintf("missing fixed system tx selector %s", methodName)) + } + return selector +} + +func (p *Parlia) BlockTimeUpperCheck(chain consensus.ChainHeaderReader, header *types.Header) error { + number := header.Number.Uint64() + snap, err := p.snapshot(chain, number-1, header.ParentHash, nil) + if err != nil { + return err + } + + parent := chain.GetHeader(header.ParentHash, number-1) + if parent == nil { + return consensus.ErrUnknownAncestor + } + + maxAllowed := p.blockTimeForRamanujanFork(snap, header, parent) + if header.MilliTimestamp() > maxAllowed { + return fmt.Errorf("BidBlock time too far in future: headerTime=%d, maxAllowed=%d", + header.MilliTimestamp(), maxAllowed) + } + return nil +} + +func txSelector(tx *types.Transaction) []byte { + data := tx.Data() + if len(data) < 4 { + return data + } + return data[:4] +} + +func isZeroSig(v, r, s *big.Int) bool { + isZero := func(x *big.Int) bool { return x == nil || x.Sign() == 0 } + return isZero(v) && isZero(r) && isZero(s) +} diff --git a/consensus/parlia/bid_block_test.go b/consensus/parlia/bid_block_test.go new file mode 100644 index 0000000000..be93e06ed5 --- /dev/null +++ b/consensus/parlia/bid_block_test.go @@ -0,0 +1,85 @@ +// Copyright 2026 The go-ethereum Authors +// This file is part of the go-ethereum library. + +package parlia + +import ( + "math/big" + "testing" + + "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/core/systemcontracts" + "github.com/ethereum/go-ethereum/core/types" + buildertypes "github.com/ethereum/go-ethereum/core/types/builder" +) + +// sysTx builds an unsigned system-tx candidate: to=ValidatorContract, gasPrice=0, +// zero signature, data prefixed with the given selector. +func sysTx(selector []byte, value *big.Int) *types.Transaction { + to := common.HexToAddress(systemcontracts.ValidatorContract) + return types.NewTx(&types.LegacyTx{ + GasPrice: big.NewInt(0), + Gas: 100000, + To: &to, + Value: value, + Data: selector, + }) +} + +// userTx is a normal user tx (nonzero gasPrice, non-system recipient): never a +// system-tx candidate, so it stops the trailing-region scan. +func userTx() *types.Transaction { + to := common.HexToAddress("0x1111111111111111111111111111111111111111") + return types.NewTx(&types.LegacyTx{GasPrice: big.NewInt(1), Gas: 21000, To: &to, Value: big.NewInt(0)}) +} + +func TestVerifyBidBlockSystemTxs(t *testing.T) { + p := &Parlia{} + // Number 100 (not a multiple of finalityRewardInterval=200) + same-UTC-day + // timestamps (not a breathe block) => expected shape is exactly [deposit]. + header := &types.Header{Number: big.NewInt(100), Time: 1003} + parent := &types.Header{Number: big.NewInt(99), Time: 1000} + + depositSel := signableSystemTxSelectors["deposit"] + finalitySel := signableSystemTxSelectors["distributeFinalityReward"] + deposit := func(v int64) *types.Transaction { return sysTx(depositSel[:], big.NewInt(v)) } + + tests := []struct { + name string + txs types.Transactions + sysStart int + wantErr bool + }{ + {"valid [deposit]", types.Transactions{userTx(), deposit(5)}, 1, false}, + {"non-whitelist selector", types.Transactions{userTx(), sysTx([]byte{0xde, 0xad, 0xbe, 0xef}, big.NewInt(5))}, 1, true}, + {"wrong order (finalityReward where deposit expected)", types.Transactions{userTx(), sysTx(finalitySel[:], big.NewInt(0))}, 1, true}, + {"missing deposit (empty trailing region)", types.Transactions{userTx()}, 1, true}, + {"extra system tx", types.Transactions{userTx(), deposit(5), deposit(6)}, 1, true}, + } + for _, tc := range tests { + t.Run(tc.name, func(t *testing.T) { + decoded := &buildertypes.DecodedBidBlock{Header: header, Txs: tc.txs} + err := p.VerifyBidBlockSystemTxs(decoded, parent, tc.sysStart) + if (err != nil) != tc.wantErr { + t.Fatalf("VerifyBidBlockSystemTxs err=%v, wantErr=%v", err, tc.wantErr) + } + }) + } +} + +func TestExtractBidBlockDepositValue(t *testing.T) { + p := &Parlia{} + depositSel := signableSystemTxSelectors["deposit"] + + // systemTxStart > 0: deposit value is returned as GasFee. + start, fee := p.ExtractBidBlockDepositValue(types.Transactions{userTx(), sysTx(depositSel[:], big.NewInt(7))}) + if start != 1 || fee.Cmp(big.NewInt(7)) != 0 { + t.Fatalf("with user tx: got (start=%d, fee=%v), want (1, 7)", start, fee) + } + + // systemTxStart == 0 (no preceding user tx): GasFee must be zero so admission rejects it. + start, fee = p.ExtractBidBlockDepositValue(types.Transactions{sysTx(depositSel[:], big.NewInt(7))}) + if start != 0 || fee.Sign() != 0 { + t.Fatalf("no user tx: got (start=%d, fee=%v), want (0, 0)", start, fee) + } +} diff --git a/consensus/parlia/feynmanfork.go b/consensus/parlia/feynmanfork.go index 48bdf0ace9..832abfb262 100644 --- a/consensus/parlia/feynmanfork.go +++ b/consensus/parlia/feynmanfork.go @@ -29,9 +29,9 @@ func isBreatheBlock(lastBlockTime, blockTime uint64) bool { return lastBlockTime != 0 && !sameDayInUTC(lastBlockTime, blockTime) } -// initializeFeynmanContract initialize new contracts of Feynman fork +// initializeFeynmanContract initialize new contracts of Feynman fork. func (p *Parlia) initializeFeynmanContract(state vm.StateDB, header *types.Header, chain core.ChainContext, - txs *[]*types.Transaction, receipts *[]*types.Receipt, receivedTxs *[]*types.Transaction, usedGas *uint64, mining bool, tracer *tracing.Hooks, + txs *[]*types.Transaction, receipts *[]*types.Receipt, receivedTxs *[]*types.Transaction, usedGas *uint64, mode systemTxMode, tracer *tracing.Hooks, ) error { // method method := "initialize" @@ -54,7 +54,7 @@ func (p *Parlia) initializeFeynmanContract(state vm.StateDB, header *types.Heade msg := p.getSystemMessage(header.Coinbase, common.HexToAddress(c), data, common.Big0) // apply message log.Info("initialize feynman contract", "block number", header.Number.Uint64(), "contract", c) - err = p.applyTransaction(msg, state, header, chain, txs, receipts, receivedTxs, usedGas, mining, tracer) + err = p.applyTransaction(msg, state, header, chain, txs, receipts, receivedTxs, usedGas, mode, tracer) if err != nil { return err } @@ -97,7 +97,7 @@ func (h *ValidatorHeap) Pop() interface{} { } func (p *Parlia) updateValidatorSetV2(state vm.StateDB, header *types.Header, chain core.ChainContext, - txs *[]*types.Transaction, receipts *[]*types.Receipt, receivedTxs *[]*types.Transaction, usedGas *uint64, mining bool, tracer *tracing.Hooks, + txs *[]*types.Transaction, receipts *[]*types.Receipt, receivedTxs *[]*types.Transaction, usedGas *uint64, mode systemTxMode, tracer *tracing.Hooks, ) error { // 1. get all validators and its voting power blockNr := rpc.BlockNumberOrHashWithHash(header.ParentHash, false) @@ -124,7 +124,7 @@ func (p *Parlia) updateValidatorSetV2(state vm.StateDB, header *types.Header, ch // get system message msg := p.getSystemMessage(header.Coinbase, common.HexToAddress(systemcontracts.ValidatorContract), data, common.Big0) // apply message - return p.applyTransaction(msg, state, header, chain, txs, receipts, receivedTxs, usedGas, mining, tracer) + return p.applyTransaction(msg, state, header, chain, txs, receipts, receivedTxs, usedGas, mode, tracer) } func (p *Parlia) getValidatorElectionInfo(blockNr rpc.BlockNumberOrHash) ([]ValidatorItem, error) { diff --git a/consensus/parlia/parlia.go b/consensus/parlia/parlia.go index 4d0a9df809..07c635a600 100644 --- a/consensus/parlia/parlia.go +++ b/consensus/parlia/parlia.go @@ -264,9 +264,6 @@ type Parlia struct { validatorSetABI abi.ABI slashABI abi.ABI stakeHubABI abi.ABI - - // The fields below are for testing only - fakeDiff bool // Skip difficulty verifications } // New creates a Parlia consensus engine. @@ -288,6 +285,12 @@ func New( if err != nil { panic(err) } + for methodName, selector := range signableSystemTxSelectors { + method, ok := vABI.Methods[methodName] + if !ok || !bytes.Equal(method.ID, selector[:]) { + panic(fmt.Sprintf("invalid validator set ABI selector for %s", methodName)) + } + } sABI, err := abi.JSON(strings.NewReader(slashABI)) if err != nil { panic(err) @@ -576,23 +579,35 @@ func (p *Parlia) verifyVoteAttestation(chain consensus.ChainHeaderReader, header // looking those up from the database. This is useful for concurrently verifying // a batch of new headers. func (p *Parlia) verifyHeader(chain consensus.ChainHeaderReader, header *types.Header, parents []*types.Header) error { - if header.Number == nil { - return errUnknownBlock - } - // Don't waste time checking blocks from the future if header.Time > uint64(time.Now().Unix()) { return consensus.ErrFutureBlock } - // Check that the extra-data contains the vanity, validators and signature. + + if err := p.VerifyUnsealedHeader(chain, header, parents); err != nil { + return err + } + + // All basic checks passed, verify the seal and return + return p.verifySeal(chain, header, parents) +} + +// VerifyUnsealedHeader performs all header validity checks that do not require +// a valid seal signature. It is used to validate a locally proposed block before +// sealing: it runs the same structural, fork-rule, and cascading-field checks as +// VerifyHeader but skips verifySeal (no signature yet) and verifyVoteAttestation +// (vote attestation is embedded by the sealer and not present before sealing). +func (p *Parlia) VerifyUnsealedHeader(chain consensus.ChainHeaderReader, header *types.Header, parents []*types.Header) error { + // check extra data if len(header.Extra) < extraVanity { return errMissingVanity } if len(header.Extra) < extraVanity+extraSeal { return errMissingSignature } - - // check extra data + if header.Number == nil { + return errUnknownBlock + } number := header.Number.Uint64() epochLength, err := p.epochLength(chain, header, parents) if err != nil { @@ -618,52 +633,11 @@ func (p *Parlia) verifyHeader(chain consensus.ChainHeaderReader, header *types.H return fmt.Errorf("invalid MixDigest, have %#x, expected the last two bytes to represent milliseconds", header.MixDigest) } } + // Ensure that the block doesn't contain any uncles which are meaningless in PoA if header.UncleHash != types.EmptyUncleHash { return errInvalidUncleHash } - // Ensure that the block's difficulty is meaningful (may not be correct at this point) - if number > 0 { - if header.Difficulty == nil { - return errInvalidDifficulty - } - } - - parent, err := p.getParent(chain, header, parents) - if err != nil { - return err - } - - // Verify the block's gas usage and (if applicable) verify the base fee. - if !chain.Config().IsLondon(header.Number) { - // Verify BaseFee not present before EIP-1559 fork. - if header.BaseFee != nil { - return fmt.Errorf("invalid baseFee before fork: have %d, expected 'nil'", header.BaseFee) - } - } else if err := eip1559.VerifyEIP1559Header(chain.Config(), parent, header); err != nil { - // Verify the header's EIP-1559 attributes. - return err - } - - cancun := chain.Config().IsCancun(header.Number, header.Time) - if !cancun { - switch { - case header.ExcessBlobGas != nil: - 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.WithdrawalsHash != nil: - return fmt.Errorf("invalid WithdrawalsHash, have %#x, expected nil", header.WithdrawalsHash) - } - } else { - switch { - case !header.EmptyWithdrawalsHash(): - return errors.New("header has wrong WithdrawalsHash") - } - if err := eip4844.VerifyEIP4844Header(chain.Config(), parent, header); err != nil { - return err - } - } bohr := chain.Config().IsBohr(header.Number, header.Time) if !bohr { @@ -702,12 +676,30 @@ func (p *Parlia) verifyCascadingFields(chain consensus.ChainHeaderReader, header return nil } - parent, err := p.getParent(chain, header, parents) + snap, err := p.snapshot(chain, number-1, header.ParentHash, parents) if err != nil { return err } - snap, err := p.snapshot(chain, number-1, header.ParentHash, parents) + if _, ok := snap.Validators[header.Coinbase]; !ok { + return errUnauthorizedValidator(header.Coinbase.String()) + } + if snap.SignRecently(header.Coinbase) { + return errRecentlySigned + } + + if header.Difficulty == nil { + return errInvalidDifficulty + } + inturn := snap.inturn(header.Coinbase) + if inturn && header.Difficulty.Cmp(diffInTurn) != 0 { + return errWrongDifficulty + } + if !inturn && header.Difficulty.Cmp(diffNoTurn) != 0 { + return errWrongDifficulty + } + + parent, err := p.getParent(chain, header, parents) if err != nil { return err } @@ -717,6 +709,36 @@ func (p *Parlia) verifyCascadingFields(chain consensus.ChainHeaderReader, header return err } + // Verify the block's gas usage and (if applicable) verify the base fee. + if !chain.Config().IsLondon(header.Number) { + // Verify BaseFee not present before EIP-1559 fork. + if header.BaseFee != nil { + return fmt.Errorf("invalid baseFee before fork: have %d, expected 'nil'", header.BaseFee) + } + } else if err := eip1559.VerifyEIP1559Header(chain.Config(), parent, header); err != nil { + // Verify the header's EIP-1559 attributes. + return err + } + + cancun := chain.Config().IsCancun(header.Number, header.Time) + if !cancun { + switch { + case header.ExcessBlobGas != nil: + 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.WithdrawalsHash != nil: + return fmt.Errorf("invalid WithdrawalsHash, have %#x, expected nil", header.WithdrawalsHash) + } + } else { + if !header.EmptyWithdrawalsHash() { + return errors.New("header has wrong WithdrawalsHash") + } + if err := eip4844.VerifyEIP4844Header(chain.Config(), parent, header); err != nil { + return err + } + } + // Verify that the gas limit is <= 2^63-1 capacity := uint64(0x7fffffffffffffff) if header.GasLimit > capacity { @@ -742,18 +764,7 @@ func (p *Parlia) verifyCascadingFields(chain consensus.ChainHeaderReader, header return fmt.Errorf("invalid gas limit: have %d, want %d += %d", header.GasLimit, parent.GasLimit, limit-1) } - // Verify vote attestation for fast finality. - if err := p.verifyVoteAttestation(chain, header, parents); err != nil { - log.Warn("Verify vote attestation failed", "error", err, "hash", header.Hash(), "number", header.Number, - "parent", header.ParentHash, "coinbase", header.Coinbase, "extra", common.Bytes2Hex(header.Extra)) - verifyVoteAttestationErrorCounter.Inc(1) - if chain.Config().IsPlato(header.Number) { - return err - } - } - - // All basic checks passed, verify the seal and return - return p.verifySeal(chain, header, parents) + return nil } // snapshot retrieves the authorization snapshot at a given point in time. @@ -924,12 +935,6 @@ func (p *Parlia) VerifyRequests(header *types.Header, Requests [][]byte) error { return nil } -// VerifySeal implements consensus.Engine, checking whether the signature contained -// in the header satisfies the consensus protocol requirements. -func (p *Parlia) VerifySeal(chain consensus.ChainReader, header *types.Header) error { - return p.verifySeal(chain, header, nil) -} - // verifySeal checks whether the signature contained in the header satisfies the // consensus protocol requirements. The method accepts an optional list of parent // headers that aren't yet part of the local blockchain to generate the snapshots @@ -940,10 +945,15 @@ func (p *Parlia) verifySeal(chain consensus.ChainHeaderReader, header *types.Hea if number == 0 { return errUnknownBlock } - // Retrieve the snapshot needed to verify this header and cache it - snap, err := p.snapshot(chain, number-1, header.ParentHash, parents) - if err != nil { - return err + + // Verify vote attestation for fast finality. + if err := p.verifyVoteAttestation(chain, header, parents); err != nil { + log.Warn("Verify vote attestation failed", "error", err, "hash", header.Hash(), "number", header.Number, + "parent", header.ParentHash, "coinbase", header.Coinbase, "extra", common.Bytes2Hex(header.Extra)) + verifyVoteAttestationErrorCounter.Inc(1) + if chain.Config().IsPlato(header.Number) { + return err + } } // Resolve the authorization key and check against validators @@ -967,25 +977,6 @@ func (p *Parlia) verifySeal(chain consensus.ChainHeaderReader, header *types.Hea p.recentHeaders.Add(key, header.Hash()) } - if _, ok := snap.Validators[signer]; !ok { - return errUnauthorizedValidator(signer.String()) - } - - if snap.SignRecently(signer) { - return errRecentlySigned - } - - // Ensure that the difficulty corresponds to the turn-ness of the signer - if !p.fakeDiff { - inturn := snap.inturn(signer) - if inturn && header.Difficulty.Cmp(diffInTurn) != 0 { - return errWrongDifficulty - } - if !inturn && header.Difficulty.Cmp(diffNoTurn) != 0 { - return errWrongDifficulty - } - } - return nil } @@ -1158,6 +1149,11 @@ func (p *Parlia) NextInTurnValidator(chain consensus.ChainHeaderReader, header * // header for running the transactions on top. func (p *Parlia) Prepare(chain consensus.ChainHeaderReader, header *types.Header) error { header.Coinbase = p.val + return p.prepare(chain, header) +} + +// prepare is shared by Prepare and PrepareForBidBlock; caller sets Coinbase/Number/ParentHash. +func (p *Parlia) prepare(chain consensus.ChainHeaderReader, header *types.Header) error { header.Nonce = types.BlockNonce{} number := header.Number.Uint64() @@ -1166,29 +1162,34 @@ func (p *Parlia) Prepare(chain consensus.ChainHeaderReader, header *types.Header return err } - // Set the correct difficulty - header.Difficulty = CalcDifficulty(snap, p.val) - - // Ensure the extra data has all it's components - if len(header.Extra) < extraVanity-nextForkHashSize { - header.Extra = append(header.Extra, bytes.Repeat([]byte{0x00}, extraVanity-nextForkHashSize-len(header.Extra))...) - } + header.Difficulty = calcDifficulty(snap, header.Coinbase) - // Ensure the timestamp has the correct delay parent := chain.GetHeader(header.ParentHash, number-1) if parent == nil { return consensus.ErrUnknownAncestor } blockTime := p.blockTimeForRamanujanFork(snap, header, parent) + header.Time = blockTime / 1000 // get seconds if p.chainConfig.IsLorentz(header.Number, header.Time) { header.SetMilliseconds(blockTime % 1000) } else { header.MixDigest = common.Hash{} } + return p.SetExtraData(chain, header) +} +// SetExtraData rebuilds the validator-controlled extra-data section: +// 28-byte vanity (caller-supplied, zero-padded) + 4-byte nextForkHash + +// validators bytes (epoch only) + turnLength (epoch only, post-Bohr) + 65 reserved seal bytes. +// Caller supplies the desired vanity in header.Extra; this function pads/truncates it. +func (p *Parlia) SetExtraData(chain consensus.ChainHeaderReader, header *types.Header) error { + // 32-byte vanity prefix: pad/truncate caller's vanity bytes, then append nextForkHash. + if len(header.Extra) < extraVanity-nextForkHashSize { + header.Extra = append(header.Extra, bytes.Repeat([]byte{0x00}, extraVanity-nextForkHashSize-len(header.Extra))...) + } header.Extra = header.Extra[:extraVanity-nextForkHashSize] - nextForkHash := forkid.NextForkHash(p.chainConfig, p.genesisHash, chain.GenesisHeader().Time, number, header.Time) + nextForkHash := forkid.NextForkHash(p.chainConfig, p.genesisHash, chain.GenesisHeader().Time, header.Number.Uint64(), header.Time) header.Extra = append(header.Extra, nextForkHash[:]...) if err := p.prepareValidators(chain, header); err != nil { @@ -1279,7 +1280,7 @@ func (p *Parlia) verifyTurnLength(chain consensus.ChainHeaderReader, header *typ func (p *Parlia) distributeFinalityReward(chain consensus.ChainHeaderReader, state vm.StateDB, header *types.Header, cx core.ChainContext, txs *[]*types.Transaction, receipts *[]*types.Receipt, systemTxs *[]*types.Transaction, - usedGas *uint64, mining bool, tracer *tracing.Hooks) error { + usedGas *uint64, mode systemTxMode, tracer *tracing.Hooks) error { currentHeight := header.Number.Uint64() if currentHeight%finalityRewardInterval != 0 { return nil @@ -1350,7 +1351,7 @@ func (p *Parlia) distributeFinalityReward(chain consensus.ChainHeaderReader, sta return err } msg := p.getSystemMessage(header.Coinbase, common.HexToAddress(systemcontracts.ValidatorContract), data, common.Big0) - return p.applyTransaction(msg, state, header, cx, txs, receipts, systemTxs, usedGas, mining, tracer) + return p.applyTransaction(msg, state, header, cx, txs, receipts, systemTxs, usedGas, mode, tracer) } func (p *Parlia) EstimateGasReservedForSystemTxs(chain consensus.ChainHeaderReader, header *types.Header) uint64 { @@ -1418,7 +1419,7 @@ func (p *Parlia) Finalize(chain consensus.ChainHeaderReader, header *types.Heade systemcontracts.TryUpdateBuildInSystemContract(p.chainConfig, header.Number, parent.Time, header.Time, state, false) if p.chainConfig.IsOnFeynman(header.Number, parent.Time, header.Time) { - err := p.initializeFeynmanContract(state, header, cx, txs, receipts, systemTxs, usedGas, false, tracer) + err := p.initializeFeynmanContract(state, header, cx, txs, receipts, systemTxs, usedGas, systemTxImporting, tracer) if err != nil { return fmt.Errorf("init feynman contract failed: %v", err) } @@ -1426,7 +1427,7 @@ func (p *Parlia) Finalize(chain consensus.ChainHeaderReader, header *types.Heade // No block rewards in PoA, so the state remains as is and uncles are dropped if header.Number.Cmp(common.Big1) == 0 { - err := p.initContract(state, header, cx, txs, receipts, systemTxs, usedGas, false, tracer) + err := p.initContract(state, header, cx, txs, receipts, systemTxs, usedGas, systemTxImporting, tracer) if err != nil { return errors.New("init contract failed") } @@ -1451,7 +1452,7 @@ func (p *Parlia) Finalize(chain consensus.ChainHeaderReader, header *types.Heade if !signedRecently { log.Trace("slash validator", "block hash", header.Hash(), "address", spoiledVal) - err = p.slash(spoiledVal, state, header, cx, txs, receipts, systemTxs, usedGas, false, tracer) + err = p.slash(spoiledVal, state, header, cx, txs, receipts, systemTxs, usedGas, systemTxImporting, tracer) if err != nil { log.Error("slash validator failed", "block hash", header.Hash(), "address", spoiledVal, "err", err) } @@ -1467,13 +1468,13 @@ func (p *Parlia) Finalize(chain consensus.ChainHeaderReader, header *types.Heade intentionalDelayMiningCounter.Inc(1) log.Warn("intentional delay mining detected", "validator", val, "number", header.Number, "hash", header.Hash()) } - err = p.distributeIncoming(val, state, header, cx, txs, receipts, systemTxs, usedGas, false, tracer) + err = p.distributeIncoming(val, state, header, cx, txs, receipts, systemTxs, usedGas, systemTxImporting, tracer) if err != nil { return err } if p.chainConfig.IsPlato(header.Number) { - if err := p.distributeFinalityReward(chain, state, header, cx, txs, receipts, systemTxs, usedGas, false, tracer); err != nil { + if err := p.distributeFinalityReward(chain, state, header, cx, txs, receipts, systemTxs, usedGas, systemTxImporting, tracer); err != nil { return err } } @@ -1482,7 +1483,7 @@ func (p *Parlia) Finalize(chain consensus.ChainHeaderReader, header *types.Heade if p.chainConfig.IsFeynman(header.Number, header.Time) && isBreatheBlock(parent.Time, header.Time) { // we should avoid update validators in the Feynman upgrade block if !p.chainConfig.IsOnFeynman(header.Number, parent.Time, header.Time) { - if err := p.updateValidatorSetV2(state, header, cx, txs, receipts, systemTxs, usedGas, false, tracer); err != nil { + if err := p.updateValidatorSetV2(state, header, cx, txs, receipts, systemTxs, usedGas, systemTxImporting, tracer); err != nil { return err } } @@ -1494,10 +1495,21 @@ func (p *Parlia) Finalize(chain consensus.ChainHeaderReader, header *types.Heade return nil } -// FinalizeAndAssemble implements consensus.Engine, ensuring no uncles are set, -// nor block rewards given, and returns the final block. +type systemTxMode uint8 + +const ( + systemTxImporting systemTxMode = iota + systemTxMining + systemTxPacking +) + func (p *Parlia) FinalizeAndAssemble(chain consensus.ChainHeaderReader, header *types.Header, state *state.StateDB, body *types.Body, receipts []*types.Receipt, tracer *tracing.Hooks) (*types.Block, []*types.Receipt, error) { + return p.finalizeAndAssemble(chain, header, state, body, receipts, tracer, systemTxMining) +} + +func (p *Parlia) finalizeAndAssemble(chain consensus.ChainHeaderReader, header *types.Header, state *state.StateDB, + body *types.Body, receipts []*types.Receipt, tracer *tracing.Hooks, mode systemTxMode) (*types.Block, []*types.Receipt, error) { // No block rewards in PoA, so the state remains as is and uncles are dropped cx := chainContext{ChainHeaderReader: chain, parlia: p} @@ -1516,14 +1528,14 @@ func (p *Parlia) FinalizeAndAssemble(chain consensus.ChainHeaderReader, header * systemcontracts.TryUpdateBuildInSystemContract(p.chainConfig, header.Number, parent.Time, header.Time, state, false) if p.chainConfig.IsOnFeynman(header.Number, parent.Time, header.Time) { - err := p.initializeFeynmanContract(state, header, cx, &body.Transactions, &receipts, nil, &header.GasUsed, true, tracer) + err := p.initializeFeynmanContract(state, header, cx, &body.Transactions, &receipts, nil, &header.GasUsed, mode, tracer) if err != nil { return nil, nil, fmt.Errorf("init feynman contract failed: %v", err) } } if header.Number.Cmp(common.Big1) == 0 { - err := p.initContract(state, header, cx, &body.Transactions, &receipts, nil, &header.GasUsed, true, tracer) + err := p.initContract(state, header, cx, &body.Transactions, &receipts, nil, &header.GasUsed, mode, tracer) if err != nil { return nil, nil, errors.New("init contract failed") } @@ -1547,20 +1559,20 @@ func (p *Parlia) FinalizeAndAssemble(chain consensus.ChainHeaderReader, header * } } if !signedRecently { - err = p.slash(spoiledVal, state, header, cx, &body.Transactions, &receipts, nil, &header.GasUsed, true, tracer) + err = p.slash(spoiledVal, state, header, cx, &body.Transactions, &receipts, nil, &header.GasUsed, mode, tracer) if err != nil { log.Error("slash validator failed", "block hash", header.Hash(), "address", spoiledVal) } } } - err := p.distributeIncoming(p.val, state, header, cx, &body.Transactions, &receipts, nil, &header.GasUsed, true, tracer) + err := p.distributeIncoming(header.Coinbase, state, header, cx, &body.Transactions, &receipts, nil, &header.GasUsed, mode, tracer) if err != nil { return nil, nil, err } if p.chainConfig.IsPlato(header.Number) { - if err := p.distributeFinalityReward(chain, state, header, cx, &body.Transactions, &receipts, nil, &header.GasUsed, true, tracer); err != nil { + if err := p.distributeFinalityReward(chain, state, header, cx, &body.Transactions, &receipts, nil, &header.GasUsed, mode, tracer); err != nil { return nil, nil, err } } @@ -1569,7 +1581,7 @@ func (p *Parlia) FinalizeAndAssemble(chain consensus.ChainHeaderReader, header * if p.chainConfig.IsFeynman(header.Number, header.Time) && isBreatheBlock(parent.Time, header.Time) { // we should avoid update validators in the Feynman upgrade block if !p.chainConfig.IsOnFeynman(header.Number, parent.Time, header.Time) { - if err := p.updateValidatorSetV2(state, header, cx, &body.Transactions, &receipts, nil, &header.GasUsed, true, tracer); err != nil { + if err := p.updateValidatorSetV2(state, header, cx, &body.Transactions, &receipts, nil, &header.GasUsed, mode, tracer); err != nil { return nil, nil, err } } @@ -1667,6 +1679,15 @@ func (p *Parlia) Authorize(val common.Address, signFn SignerFn, signTxFn SignerT p.signTxFn = signTxFn } +// IsLastBlockInTurn reports whether header is the last block in the current validator's turn. +func (p *Parlia) IsLastBlockInTurn(chain consensus.ChainReader, header *types.Header) bool { + snap, err := p.snapshot(chain, header.Number.Uint64()-1, header.ParentHash, nil) + if err != nil { + return false + } + return snap.lastBlockInOneTurn(header.Number.Uint64()) +} + // Argument leftOver is the time reserved for block finalize(calculate root, distribute income...) func (p *Parlia) Delay(chain consensus.ChainReader, header *types.Header, leftOver *time.Duration) *time.Duration { snap, err := p.snapshot(chain, header.Number.Uint64()-1, header.ParentHash, nil) @@ -1675,11 +1696,7 @@ func (p *Parlia) Delay(chain consensus.ChainReader, header *types.Header, leftOv } delay := p.delayForRamanujanFork(snap, header) - // The blocking time should be no more than half of period when snap.TurnLength == 1 - timeForMining := time.Duration(snap.BlockInterval) * time.Millisecond / 2 - if !snap.lastBlockInOneTurn(header.Number.Uint64()) { - timeForMining = time.Duration(snap.BlockInterval) * time.Millisecond - } + timeForMining := time.Duration(snap.BlockInterval) * time.Millisecond if delay > timeForMining { delay = timeForMining } @@ -1785,71 +1802,6 @@ func (p *Parlia) Seal(chain consensus.ChainHeaderReader, block *types.Block, res return nil } -func (p *Parlia) SignBAL(blockAccessList *types.BlockAccessListEncode) error { - p.lock.RLock() - val, signFn := p.val, p.signFn - p.lock.RUnlock() - - data, err := rlp.EncodeToBytes([]interface{}{blockAccessList.Version, blockAccessList.Number, blockAccessList.Hash, blockAccessList.Accounts}) - if err != nil { - log.Error("Encode to bytes failed when sealing", "err", err) - return errors.New("encode to bytes failed") - } - - if len(data) > int(params.MaxBALSize) { - log.Error("data is too large", "dataSize", len(data), "maxSize", params.MaxBALSize) - return errors.New("data is too large") - } - - sig, err := signFn(accounts.Account{Address: val}, accounts.MimetypeParlia, data) - if err != nil { - log.Error("Sign for the block header failed when sealing", "err", err) - return errors.New("sign for the block header failed") - } - - copy(blockAccessList.SignData, sig) - return nil -} - -func (p *Parlia) VerifyBAL(block *types.Block, bal *types.BlockAccessListEncode) error { - if bal.Version != 0 { - log.Error("invalid BAL version", "version", bal.Version) - return errors.New("invalid BAL version") - } - - if len(bal.SignData) != 65 { - log.Error("invalid BAL signature", "signatureSize", len(bal.SignData)) - return errors.New("invalid BAL signature") - } - - // Recover the public key and the Ethereum address - data, err := rlp.EncodeToBytes([]interface{}{bal.Version, block.Number(), block.Hash(), bal.Accounts}) - if err != nil { - log.Error("encode to bytes failed", "err", err) - return errors.New("encode to bytes failed") - } - - if len(data) > int(params.MaxBALSize) { - log.Error("data is too large", "dataSize", len(data), "maxSize", params.MaxBALSize) - return errors.New("data is too large") - } - - pubkey, err := crypto.Ecrecover(crypto.Keccak256(data), bal.SignData) - if err != nil { - return err - } - var pubkeyAddr common.Address - copy(pubkeyAddr[:], crypto.Keccak256(pubkey[1:])[12:]) - - signer := block.Header().Coinbase - if signer != pubkeyAddr { - log.Error("BAL signer mismatch", "signer", signer, "pubkeyAddr", pubkeyAddr, "bal.Number", bal.Number, "bal.Hash", bal.Hash) - return errors.New("signer mismatch") - } - - return nil -} - func (p *Parlia) shouldWaitForCurrentBlockProcess(chain consensus.ChainHeaderReader, header *types.Header, snap *Snapshot) bool { if header.Difficulty.Cmp(diffInTurn) == 0 { return false @@ -1900,13 +1852,13 @@ func (p *Parlia) CalcDifficulty(chain consensus.ChainHeaderReader, time uint64, if err != nil { return nil } - return CalcDifficulty(snap, p.val) + return calcDifficulty(snap, p.val) } // CalcDifficulty is the difficulty adjustment algorithm. It returns the difficulty // that a new block should have based on the previous blocks in the chain and the // current signer. -func CalcDifficulty(snap *Snapshot, signer common.Address) *big.Int { +func calcDifficulty(snap *Snapshot, signer common.Address) *big.Int { if snap.inturn(signer) { return new(big.Int).Set(diffInTurn) } @@ -2027,7 +1979,7 @@ func (p *Parlia) isIntentionalDelayMining(chain consensus.ChainHeaderReader, hea // distributeIncoming distributes system incoming of the block func (p *Parlia) distributeIncoming(val common.Address, state vm.StateDB, header *types.Header, chain core.ChainContext, - txs *[]*types.Transaction, receipts *[]*types.Receipt, receivedTxs *[]*types.Transaction, usedGas *uint64, mining bool, tracer *tracing.Hooks) error { + txs *[]*types.Transaction, receipts *[]*types.Receipt, receivedTxs *[]*types.Transaction, usedGas *uint64, mode systemTxMode, tracer *tracing.Hooks) error { coinbase := header.Coinbase doDistributeSysReward := !p.chainConfig.IsKepler(header.Number, header.Time) && @@ -2039,7 +1991,7 @@ func (p *Parlia) distributeIncoming(val common.Address, state vm.StateDB, header if rewards.Cmp(common.U2560) > 0 { state.SetBalance(consensus.SystemAddress, balance.Sub(balance, rewards), tracing.BalanceChangeUnspecified) state.AddBalance(coinbase, rewards, tracing.BalanceChangeUnspecified) - err := p.distributeToSystem(rewards.ToBig(), state, header, chain, txs, receipts, receivedTxs, usedGas, mining, tracer) + err := p.distributeToSystem(rewards.ToBig(), state, header, chain, txs, receipts, receivedTxs, usedGas, mode, tracer) if err != nil { return err } @@ -2055,12 +2007,12 @@ func (p *Parlia) distributeIncoming(val common.Address, state vm.StateDB, header state.SetBalance(consensus.SystemAddress, common.U2560, tracing.BalanceDecreaseBSCDistributeReward) state.AddBalance(coinbase, balance, tracing.BalanceIncreaseBSCDistributeReward) log.Trace("distribute to validator contract", "block hash", header.Hash(), "amount", balance) - return p.distributeToValidator(balance.ToBig(), val, state, header, chain, txs, receipts, receivedTxs, usedGas, mining, tracer) + return p.distributeToValidator(balance.ToBig(), val, state, header, chain, txs, receipts, receivedTxs, usedGas, mode, tracer) } // slash spoiled validators func (p *Parlia) slash(spoiledVal common.Address, state vm.StateDB, header *types.Header, chain core.ChainContext, - txs *[]*types.Transaction, receipts *[]*types.Receipt, receivedTxs *[]*types.Transaction, usedGas *uint64, mining bool, tracer *tracing.Hooks) error { + txs *[]*types.Transaction, receipts *[]*types.Receipt, receivedTxs *[]*types.Transaction, usedGas *uint64, mode systemTxMode, tracer *tracing.Hooks) error { // method method := "slash" @@ -2075,12 +2027,12 @@ func (p *Parlia) slash(spoiledVal common.Address, state vm.StateDB, header *type // get system message msg := p.getSystemMessage(header.Coinbase, common.HexToAddress(systemcontracts.SlashContract), data, common.Big0) // apply message - return p.applyTransaction(msg, state, header, chain, txs, receipts, receivedTxs, usedGas, mining, tracer) + return p.applyTransaction(msg, state, header, chain, txs, receipts, receivedTxs, usedGas, mode, tracer) } // init contract func (p *Parlia) initContract(state vm.StateDB, header *types.Header, chain core.ChainContext, - txs *[]*types.Transaction, receipts *[]*types.Receipt, receivedTxs *[]*types.Transaction, usedGas *uint64, mining bool, tracer *tracing.Hooks) error { + txs *[]*types.Transaction, receipts *[]*types.Receipt, receivedTxs *[]*types.Transaction, usedGas *uint64, mode systemTxMode, tracer *tracing.Hooks) error { // method method := "init" // contracts @@ -2103,7 +2055,7 @@ func (p *Parlia) initContract(state vm.StateDB, header *types.Header, chain core msg := p.getSystemMessage(header.Coinbase, common.HexToAddress(c), data, common.Big0) // apply message log.Trace("init contract", "block hash", header.Hash(), "contract", c) - err = p.applyTransaction(msg, state, header, chain, txs, receipts, receivedTxs, usedGas, mining, tracer) + err = p.applyTransaction(msg, state, header, chain, txs, receipts, receivedTxs, usedGas, mode, tracer) if err != nil { return err } @@ -2112,17 +2064,17 @@ func (p *Parlia) initContract(state vm.StateDB, header *types.Header, chain core } func (p *Parlia) distributeToSystem(amount *big.Int, state vm.StateDB, header *types.Header, chain core.ChainContext, - txs *[]*types.Transaction, receipts *[]*types.Receipt, receivedTxs *[]*types.Transaction, usedGas *uint64, mining bool, tracer *tracing.Hooks) error { + txs *[]*types.Transaction, receipts *[]*types.Receipt, receivedTxs *[]*types.Transaction, usedGas *uint64, mode systemTxMode, tracer *tracing.Hooks) error { // get system message msg := p.getSystemMessage(header.Coinbase, common.HexToAddress(systemcontracts.SystemRewardContract), nil, amount) // apply message - return p.applyTransaction(msg, state, header, chain, txs, receipts, receivedTxs, usedGas, mining, tracer) + return p.applyTransaction(msg, state, header, chain, txs, receipts, receivedTxs, usedGas, mode, tracer) } // distributeToValidator deposits validator reward to validator contract func (p *Parlia) distributeToValidator(amount *big.Int, validator common.Address, state vm.StateDB, header *types.Header, chain core.ChainContext, - txs *[]*types.Transaction, receipts *[]*types.Receipt, receivedTxs *[]*types.Transaction, usedGas *uint64, mining bool, tracer *tracing.Hooks) error { + txs *[]*types.Transaction, receipts *[]*types.Receipt, receivedTxs *[]*types.Transaction, usedGas *uint64, mode systemTxMode, tracer *tracing.Hooks) error { // method method := "deposit" @@ -2137,7 +2089,7 @@ func (p *Parlia) distributeToValidator(amount *big.Int, validator common.Address // get system message msg := p.getSystemMessage(header.Coinbase, common.HexToAddress(systemcontracts.ValidatorContract), data, amount) // apply message - return p.applyTransaction(msg, state, header, chain, txs, receipts, receivedTxs, usedGas, mining, tracer) + return p.applyTransaction(msg, state, header, chain, txs, receipts, receivedTxs, usedGas, mode, tracer) } // get system message @@ -2158,20 +2110,25 @@ func (p *Parlia) applyTransaction( header *types.Header, chainContext core.ChainContext, txs *[]*types.Transaction, receipts *[]*types.Receipt, - receivedTxs *[]*types.Transaction, usedGas *uint64, mining bool, + receivedTxs *[]*types.Transaction, usedGas *uint64, mode systemTxMode, tracer *tracing.Hooks, ) (applyErr error) { nonce := state.GetNonce(msg.From) expectedTx := types.NewTransaction(nonce, *msg.To, msg.Value, msg.GasLimit, msg.GasPrice, msg.Data) expectedHash := p.signer.Hash(expectedTx) - if msg.From == p.val && mining { + switch mode { + case systemTxMining: var err error + if msg.From != p.val { + return fmt.Errorf("cannot sign system tx from %s with validator %s", msg.From, p.val) + } expectedTx, err = p.signTxFn(accounts.Account{Address: msg.From}, expectedTx, p.chainConfig.ChainID) if err != nil { return err } - } else { + case systemTxPacking: + case systemTxImporting: if receivedTxs == nil || len(*receivedTxs) == 0 || (*receivedTxs)[0] == nil { return errors.New("supposed to get a actual transaction, but get none") } @@ -2189,6 +2146,8 @@ func (p *Parlia) applyTransaction( expectedTx = actualTx // move to next *receivedTxs = (*receivedTxs)[1:] + default: + return fmt.Errorf("unknown system tx mode %d", mode) } state.SetTxContext(expectedTx.Hash(), len(*txs)) diff --git a/consensus/parlia/parlia_test.go b/consensus/parlia/parlia_test.go index 92b3691613..c1fad5e51b 100644 --- a/consensus/parlia/parlia_test.go +++ b/consensus/parlia/parlia_test.go @@ -1,6 +1,7 @@ package parlia import ( + "bytes" "crypto/ecdsa" "crypto/rand" "fmt" @@ -9,6 +10,7 @@ import ( "slices" "strings" "testing" + "time" "github.com/ethereum/go-ethereum/accounts" "github.com/ethereum/go-ethereum/common" @@ -16,6 +18,7 @@ import ( "github.com/ethereum/go-ethereum/consensus" "github.com/ethereum/go-ethereum/consensus/misc/eip4844" "github.com/ethereum/go-ethereum/core" + "github.com/ethereum/go-ethereum/core/forkid" "github.com/ethereum/go-ethereum/core/rawdb" "github.com/ethereum/go-ethereum/core/state" "github.com/ethereum/go-ethereum/core/systemcontracts" @@ -619,16 +622,15 @@ func TestSimulateP2P(t *testing.T) { if err != nil { t.Fatalf("[Testcase %d] simulate P2P error: %v", index, err) } - /* - for _, val := range c.validators { - t.Logf("[Testcase %d] validator(%d) head block: %d", - index, val.index, val.head.blockNumber) - t.Logf("[Testcase %d] validator(%d) highest justified block: %d", - index, val.index, val.head.GetJustifiedNumber()) - t.Logf("[Testcase %d] validator(%d) highest finalized block: %d", - index, val.index, val.head.GetFinalizedBlock().blockNumber) - } - */ + for _, val := range c.validators { + t.Logf("[Testcase %d] validator(%d) head block: %d", + index, val.index, val.head.blockNumber) + t.Logf("[Testcase %d] validator(%d) highest justified block: %d", + index, val.index, val.head.GetJustifiedNumber()) + t.Logf("[Testcase %d] validator(%d) highest finalized block: %d", + index, val.index, val.head.GetFinalizedBlock().blockNumber) + } + if c.CheckChain() == false { t.Fatalf("[Testcase %d] chain not works as expected", index) } @@ -705,7 +707,7 @@ func TestParlia_applyTransactionTracing(t *testing.T) { hooks := recording.hooks() cx := chainContext{ChainHeaderReader: chain, parlia: engine} - applyErr := engine.applyTransaction(msg, state.NewHookedState(stateDB, hooks), bs[0].Header(), cx, &txs, &receipts, &receivedTxs, &usedGas, false, hooks) + applyErr := engine.applyTransaction(msg, state.NewHookedState(stateDB, hooks), bs[0].Header(), cx, &txs, &receipts, &receivedTxs, &usedGas, systemTxImporting, hooks) if applyErr != nil { t.Fatalf("failed to apply system contract transaction: %v", applyErr) } @@ -725,6 +727,430 @@ func TestParlia_applyTransactionTracing(t *testing.T) { } } +func TestParlia_applyTransactionModes(t *testing.T) { + frdir := t.TempDir() + db, err := rawdb.NewDatabaseWithFreezer(rawdb.NewMemoryDatabase(), frdir, "", false) + if err != nil { + t.Fatalf("failed to create database with ancient backend: %v", err) + } + + trieDB := triedb.NewDatabase(db, nil) + defer trieDB.Close() + + config := params.ParliaTestChainConfig + gspec := &core.Genesis{ + Config: config, + Alloc: types.GenesisAlloc{testAddr: {Balance: new(big.Int).SetUint64(10 * params.Ether)}}, + } + mockEngine := &mockParlia{} + genesisBlock := gspec.MustCommit(db, trieDB) + chain, _ := core.NewBlockChain(db, gspec, mockEngine, nil) + defer chain.Stop() + parents, _ := core.GenerateChain(config, genesisBlock, mockEngine, db, 1, nil) + header := parents[0].Header() + + engine := New(config, db, nil, genesisBlock.Hash()) + validatorKey, err := crypto.GenerateKey() + if err != nil { + t.Fatalf("failed to generate validator key: %v", err) + } + validator := crypto.PubkeyToAddress(validatorKey.PublicKey) + engine.Authorize(validator, nil, func(account accounts.Account, tx *types.Transaction, chainID *big.Int) (*types.Transaction, error) { + if account.Address != validator { + return nil, fmt.Errorf("unexpected signing account %s", account.Address) + } + return types.SignTx(tx, types.LatestSigner(config), validatorKey) + }) + + data, err := engine.validatorSetABI.Pack("distributeFinalityReward", make([]common.Address, 0), make([]*big.Int, 0)) + if err != nil { + t.Fatalf("failed to pack system contract method: %v", err) + } + msg := engine.getSystemMessage(validator, common.HexToAddress(systemcontracts.ValidatorContract), data, common.Big0) + cx := chainContext{ChainHeaderReader: chain, parlia: engine} + + newState := func(t *testing.T) *state.StateDB { + t.Helper() + stateDB, err := state.New(genesisBlock.Root(), state.NewDatabase(trieDB, nil)) + if err != nil { + t.Fatalf("failed to create stateDB: %v", err) + } + return stateDB + } + expectedTx := func(stateDB *state.StateDB) *types.Transaction { + nonce := stateDB.GetNonce(msg.From) + return types.NewTransaction(nonce, *msg.To, msg.Value, msg.GasLimit, msg.GasPrice, msg.Data) + } + apply := func(t *testing.T, stateDB *state.StateDB, receivedTxs *[]*types.Transaction, mode systemTxMode) ([]*types.Transaction, error) { + t.Helper() + txs := make([]*types.Transaction, 0, 1) + receipts := make([]*types.Receipt, 0, 1) + usedGas := uint64(0) + err := engine.applyTransaction(msg, stateDB, header, cx, &txs, &receipts, receivedTxs, &usedGas, mode, nil) + return txs, err + } + + t.Run("mining signs system tx from validator", func(t *testing.T) { + txs, err := apply(t, newState(t), nil, systemTxMining) + if err != nil { + t.Fatalf("applyTransaction mining failed: %v", err) + } + if len(txs) != 1 { + t.Fatalf("expected one tx, got %d", len(txs)) + } + if isUnsignedTx(txs[0]) { + t.Fatalf("mining mode must sign system tx") + } + }) + + t.Run("mining rejects non-validator sender", func(t *testing.T) { + original := msg.From + msg.From = common.HexToAddress("0x3000000000000000000000000000000000000003") + defer func() { msg.From = original }() + + _, err := apply(t, newState(t), nil, systemTxMining) + if err == nil || !strings.Contains(err.Error(), "cannot sign system tx") { + t.Fatalf("expected cannot sign error, got %v", err) + } + }) + + t.Run("packing keeps system tx unsigned", func(t *testing.T) { + txs, err := apply(t, newState(t), nil, systemTxPacking) + if err != nil { + t.Fatalf("applyTransaction packing failed: %v", err) + } + if len(txs) != 1 { + t.Fatalf("expected one tx, got %d", len(txs)) + } + if !isUnsignedTx(txs[0]) { + t.Fatalf("packing mode must keep system tx unsigned") + } + }) + + t.Run("importing consumes matching received tx", func(t *testing.T) { + stateDB := newState(t) + receivedTxs := []*types.Transaction{expectedTx(stateDB)} + txs, err := apply(t, stateDB, &receivedTxs, systemTxImporting) + if err != nil { + t.Fatalf("applyTransaction importing failed: %v", err) + } + if len(receivedTxs) != 0 { + t.Fatalf("expected received tx to be consumed, got %d left", len(receivedTxs)) + } + if len(txs) != 1 || txs[0] == nil { + t.Fatalf("expected imported tx to be appended") + } + }) + + t.Run("importing rejects missing received tx", func(t *testing.T) { + receivedTxs := []*types.Transaction{} + _, err := apply(t, newState(t), &receivedTxs, systemTxImporting) + if err == nil || !strings.Contains(err.Error(), "supposed to get a actual transaction") { + t.Fatalf("expected missing received tx error, got %v", err) + } + }) + + t.Run("importing rejects mismatched received tx", func(t *testing.T) { + stateDB := newState(t) + expected := expectedTx(stateDB) + wrongTx := types.NewTransaction(expected.Nonce()+1, *expected.To(), expected.Value(), expected.Gas(), expected.GasPrice(), expected.Data()) + receivedTxs := []*types.Transaction{wrongTx} + _, err := apply(t, stateDB, &receivedTxs, systemTxImporting) + if err == nil || !strings.Contains(err.Error(), "expected tx hash") { + t.Fatalf("expected tx hash mismatch error, got %v", err) + } + }) +} + +func isUnsignedTx(tx *types.Transaction) bool { + v, r, s := tx.RawSignatureValues() + return v.Sign() == 0 && r.Sign() == 0 && s.Sign() == 0 +} + +// TestParliaFinalizeAndAssembleBidBlock verifies BidBlock assembly emits unsigned system txs. +func TestParliaFinalizeAndAssembleBidBlock(t *testing.T) { + frdir := t.TempDir() + db, err := rawdb.NewDatabaseWithFreezer(rawdb.NewMemoryDatabase(), frdir, "", false) + if err != nil { + t.Fatalf("failed to create database with ancient backend: %v", err) + } + + trieDB := triedb.NewDatabase(db, nil) + defer trieDB.Close() + + config := params.ParliaTestChainConfig + gspec := &core.Genesis{ + Config: config, + Alloc: types.GenesisAlloc{testAddr: {Balance: new(big.Int).SetUint64(10 * params.Ether)}}, + } + mockEngine := &mockParlia{} + genesisBlock := gspec.MustCommit(db, trieDB) + chain, _ := core.NewBlockChain(db, gspec, mockEngine, nil) + defer chain.Stop() + parents, _ := core.GenerateChain(config, genesisBlock, mockEngine, db, 1, nil) + parent := parents[0] + rawdb.WriteBlock(db, parent) + + engine := New(config, db, nil, genesisBlock.Hash()) + validatorKey, err := crypto.GenerateKey() + if err != nil { + t.Fatalf("failed to generate key: %v", err) + } + validator := crypto.PubkeyToAddress(validatorKey.PublicKey) + engine.Authorize(validator, nil, func(account accounts.Account, tx *types.Transaction, chainID *big.Int) (*types.Transaction, error) { + if account.Address != validator { + return nil, fmt.Errorf("unexpected signing account %s", account.Address) + } + return types.SignTx(tx, types.LatestSigner(config), validatorKey) + }) + + gasFee := uint256.NewInt(12345) + newHeader := func() *types.Header { + return &types.Header{ + ParentHash: parent.Hash(), + Number: new(big.Int).Add(parent.Number(), common.Big1), + Coinbase: validator, + Difficulty: new(big.Int).Set(diffInTurn), + GasLimit: params.SystemTxsGasHardLimit, + Time: parent.Time() + 1, + } + } + newState := func() *state.StateDB { + stateDB, err := state.New(parent.Root(), state.NewDatabase(trieDB, nil)) + if err != nil { + t.Fatalf("failed to create stateDB: %v", err) + } + stateDB.SetBalance(consensus.SystemAddress, new(uint256.Int).Set(gasFee), tracing.BalanceChangeUnspecified) + return stateDB + } + + signedBlock, signedReceipts, err := engine.FinalizeAndAssemble(chain, newHeader(), newState(), &types.Body{}, nil, nil) + if err != nil { + t.Fatalf("failed to finalize signed block: %v", err) + } + unsignedBlock, unsignedReceipts, err := engine.FinalizeAndAssembleBidBlock(chain, newHeader(), newState(), &types.Body{}, nil, nil) + if err != nil { + t.Fatalf("failed to finalize BidBlock: %v", err) + } + + if signedBlock.Root() != unsignedBlock.Root() { + t.Fatalf("state root mismatch: signed=%s unsigned=%s", signedBlock.Root(), unsignedBlock.Root()) + } + if signedBlock.ReceiptHash() != unsignedBlock.ReceiptHash() { + t.Fatalf("receipt hash mismatch: signed=%s unsigned=%s", signedBlock.ReceiptHash(), unsignedBlock.ReceiptHash()) + } + if signedBlock.Bloom() != unsignedBlock.Bloom() { + t.Fatalf("receipt bloom mismatch") + } + if signedBlock.GasUsed() != unsignedBlock.GasUsed() { + t.Fatalf("gas used mismatch: signed=%d unsigned=%d", signedBlock.GasUsed(), unsignedBlock.GasUsed()) + } + if len(signedBlock.Transactions()) == 0 || len(unsignedBlock.Transactions()) == 0 { + t.Fatalf("expected system transactions in both finalized blocks") + } + if isUnsignedTx(signedBlock.Transactions()[0]) { + t.Fatalf("expected default finalize path to sign system txs") + } + if !isUnsignedTx(unsignedBlock.Transactions()[0]) { + t.Fatalf("expected BidBlock assembly to keep system txs unsigned") + } + if len(signedReceipts) != len(unsignedReceipts) { + t.Fatalf("receipt count mismatch: signed=%d unsigned=%d", len(signedReceipts), len(unsignedReceipts)) + } +} + +func TestParliaFinalizeAndAssembleBidBlockRewardsHeaderCoinbase(t *testing.T) { + frdir := t.TempDir() + db, err := rawdb.NewDatabaseWithFreezer(rawdb.NewMemoryDatabase(), frdir, "", false) + if err != nil { + t.Fatalf("failed to create database with ancient backend: %v", err) + } + + trieDB := triedb.NewDatabase(db, nil) + defer trieDB.Close() + + config := params.ParliaTestChainConfig + gspec := &core.Genesis{ + Config: config, + Alloc: types.GenesisAlloc{testAddr: {Balance: new(big.Int).SetUint64(10 * params.Ether)}}, + } + mockEngine := &mockParlia{} + genesisBlock := gspec.MustCommit(db, trieDB) + chain, _ := core.NewBlockChain(db, gspec, mockEngine, nil) + defer chain.Stop() + parents, _ := core.GenerateChain(config, genesisBlock, mockEngine, db, 1, nil) + parent := parents[0] + rawdb.WriteBlock(db, parent) + + engine := New(config, db, nil, genesisBlock.Hash()) + localValidator := common.HexToAddress("0x1000000000000000000000000000000000000001") + blockCoinbase := common.HexToAddress("0x2000000000000000000000000000000000000002") + engine.Authorize(localValidator, nil, nil) + + header := &types.Header{ + ParentHash: parent.Hash(), + Number: new(big.Int).Add(parent.Number(), common.Big1), + Coinbase: blockCoinbase, + Difficulty: new(big.Int).Set(diffInTurn), + GasLimit: params.SystemTxsGasHardLimit, + Time: parent.Time() + 1, + } + stateDB, err := state.New(parent.Root(), state.NewDatabase(trieDB, nil)) + if err != nil { + t.Fatalf("failed to create stateDB: %v", err) + } + stateDB.SetBalance(consensus.SystemAddress, uint256.NewInt(12345), tracing.BalanceChangeUnspecified) + + block, _, err := engine.FinalizeAndAssembleBidBlock(chain, header, stateDB, &types.Body{}, nil, nil) + if err != nil { + t.Fatalf("failed to finalize BidBlock: %v", err) + } + + wantDeposit, err := engine.validatorSetABI.Pack("deposit", blockCoinbase) + if err != nil { + t.Fatalf("failed to pack expected deposit: %v", err) + } + wrongDeposit, err := engine.validatorSetABI.Pack("deposit", localValidator) + if err != nil { + t.Fatalf("failed to pack wrong deposit: %v", err) + } + var found bool + for _, tx := range block.Transactions() { + if tx.To() == nil || *tx.To() != common.HexToAddress(systemcontracts.ValidatorContract) { + continue + } + if bytes.Equal(tx.Data(), wrongDeposit) { + t.Fatalf("deposit reward routed to local p.val %s, want header coinbase %s", localValidator, blockCoinbase) + } + if bytes.Equal(tx.Data(), wantDeposit) { + found = true + } + } + if !found { + t.Fatalf("missing deposit reward for header coinbase %s", blockCoinbase) + } +} + +func TestParliaPrepareForBidBlock(t *testing.T) { + frdir := t.TempDir() + db, err := rawdb.NewDatabaseWithFreezer(rawdb.NewMemoryDatabase(), frdir, "", false) + if err != nil { + t.Fatalf("failed to create database with ancient backend: %v", err) + } + + trieDB := triedb.NewDatabase(db, nil) + defer trieDB.Close() + + config := params.ParliaTestChainConfig + otherValidator := common.HexToAddress("0x2000000000000000000000000000000000000000") + extra := make([]byte, extraVanity+validatorNumberSize+2*validatorBytesLength+extraSeal) + extra[extraVanity] = 2 + copy(extra[extraVanity+validatorNumberSize:], testAddr[:]) + copy(extra[extraVanity+validatorNumberSize+validatorBytesLength:], otherValidator[:]) + gspec := &core.Genesis{ + Config: config, + ExtraData: extra, + Timestamp: uint64(time.Now().Add(-10 * time.Second).Unix()), + Alloc: types.GenesisAlloc{testAddr: {Balance: new(big.Int).SetUint64(10 * params.Ether)}}, + } + mockEngine := &mockParlia{} + genesisBlock := gspec.MustCommit(db, trieDB) + chain, _ := core.NewBlockChain(db, gspec, mockEngine, nil) + defer chain.Stop() + + validatorEngine := New(config, db, nil, genesisBlock.Hash()) + inturnValidator, err := validatorEngine.NextInTurnValidator(chain, genesisBlock.Header()) + if err != nil { + t.Fatalf("failed to get in-turn validator: %v", err) + } + validatorEngine.Authorize(inturnValidator, nil, nil) + builderEngine := New(config, db, nil, genesisBlock.Hash()) + if inturnValidator == testAddr { + builderEngine.Authorize(otherValidator, nil, nil) + } else { + builderEngine.Authorize(testAddr, nil, nil) + } + + newHeader := func() *types.Header { + return &types.Header{ + ParentHash: genesisBlock.Hash(), + Number: common.Big1, + GasLimit: params.SystemTxsGasHardLimit, + } + } + validatorHeader := newHeader() + builderHeader := newHeader() + + if err := validatorEngine.Prepare(chain, validatorHeader); err != nil { + t.Fatalf("failed to prepare validator header: %v", err) + } + if err := builderEngine.PrepareForBidBlock(chain, builderHeader); err != nil { + t.Fatalf("failed to prepare BidBlock header: %v", err) + } + + if builderHeader.Coinbase != validatorHeader.Coinbase { + t.Fatalf("coinbase mismatch: builder=%s validator=%s", builderHeader.Coinbase, validatorHeader.Coinbase) + } + if builderHeader.Coinbase != inturnValidator { + t.Fatalf("builder coinbase mismatch: have %s want %s", builderHeader.Coinbase, inturnValidator) + } + // Prepare and PrepareForBidBlock share the prepare() core, so headers + // prepared back-to-back land on the same blockTimeForRamanujanFork output. + // Allow one 50ms quantum of tolerance for the rare case where the two + // calls straddle a wall-clock alignment tick. + diff := int64(builderHeader.MilliTimestamp()) - int64(validatorHeader.MilliTimestamp()) + if diff < 0 { + diff = -diff + } + if diff > 50 { + t.Fatalf("builder/validator time diverge by %dms: builder=%d validator=%d", + diff, builderHeader.MilliTimestamp(), validatorHeader.MilliTimestamp()) + } + if builderHeader.Difficulty.Cmp(validatorHeader.Difficulty) != 0 { + t.Fatalf("difficulty mismatch: builder=%s validator=%s", builderHeader.Difficulty, validatorHeader.Difficulty) + } + // BidBlock prepare must produce a byte-identical Extra to the normal validator + // prepare (length-equal is too weak: a wrong forkhash/vanity byte would slip through). + if !bytes.Equal(builderHeader.Extra, validatorHeader.Extra) { + t.Fatalf("extra mismatch:\n builder =%x\n validator =%x", builderHeader.Extra, validatorHeader.Extra) + } + + // SetExtraData branch checks on a non-epoch header (no validator-set contract call): + // forkhash bytes, zeroed seal space, and vanity truncation/padding. The epoch + // validators / turnLength branches require a populated validator contract and are + // covered by e2e. + const vanityLen = extraVanity - nextForkHashSize // 28 + genesisTime := chain.GenesisHeader().Time + wantForkHash := forkid.NextForkHash(config, genesisBlock.Hash(), genesisTime, validatorHeader.Number.Uint64(), validatorHeader.Time) + if got := validatorHeader.Extra[vanityLen:extraVanity]; !bytes.Equal(got, wantForkHash[:]) { + t.Fatalf("forkhash mismatch: got %x want %x", got, wantForkHash[:]) + } + if seal := validatorHeader.Extra[len(validatorHeader.Extra)-extraSeal:]; !bytes.Equal(seal, make([]byte, extraSeal)) { + t.Fatalf("seal space not zeroed: %x", seal) + } + + setExtra := func(vanity []byte) []byte { + h := newHeader() + h.Time = validatorHeader.Time + h.Extra = append([]byte(nil), vanity...) + if err := validatorEngine.SetExtraData(chain, h); err != nil { + t.Fatalf("SetExtraData: %v", err) + } + return h.Extra + } + // over-long vanity is truncated to vanityLen bytes. + long := bytes.Repeat([]byte{0xAB}, extraVanity*2) + if got := setExtra(long)[:vanityLen]; !bytes.Equal(got, long[:vanityLen]) { + t.Fatalf("vanity not truncated: got %x", got) + } + // short vanity is zero-padded to vanityLen bytes. + short := []byte{0x01, 0x02} + ext := setExtra(short) + if !bytes.Equal(ext[:len(short)], short) || !bytes.Equal(ext[len(short):vanityLen], make([]byte, vanityLen-len(short))) { + t.Fatalf("vanity not zero-padded: got %x", ext[:vanityLen]) + } +} + func formatRecords(records []string) string { indented := make([]string, 0, len(records)) for _, record := range records { @@ -860,490 +1286,3 @@ func (c *mockParlia) FinalizeAndAssemble(chain consensus.ChainHeaderReader, head func (c *mockParlia) CalcDifficulty(chain consensus.ChainHeaderReader, time uint64, parent *types.Header) *big.Int { return big.NewInt(1) } - -func TestSignBAL(t *testing.T) { - // Setup test environment - key, _ := crypto.GenerateKey() - addr := crypto.PubkeyToAddress(key.PublicKey) - - // Create mock signing function that succeeds - mockSignFn := func(account accounts.Account, mimeType string, data []byte) ([]byte, error) { - if account.Address != addr { - return nil, fmt.Errorf("wrong address") - } - if mimeType != accounts.MimetypeParlia { - return nil, fmt.Errorf("wrong mime type") - } - // Return a dummy 65-byte signature - sig := make([]byte, 65) - copy(sig, []byte("test_signature_data_for_testing_purposes_123456789012345678901234")) - return sig, nil - } - - // Create Parlia instance - parlia := &Parlia{ - val: addr, - signFn: mockSignFn, - } - - tests := []struct { - name string - bal *types.BlockAccessListEncode - expectedError bool - signFn SignerFn - description string - }{ - { - name: "successful signing", - bal: &types.BlockAccessListEncode{ - Version: 0, - SignData: make([]byte, 65), - Accounts: []types.AccountAccessListEncode{ - { - Address: common.HexToAddress("0x1234567890123456789012345678901234567890"), - StorageItems: []types.StorageAccessItem{ - {Key: common.HexToHash("0x01"), TxIndex: 0, Dirty: false}, - }, - }, - }, - }, - expectedError: false, - signFn: mockSignFn, - description: "Should successfully sign a valid BlockAccessListEncode", - }, - { - name: "signing function error", - bal: &types.BlockAccessListEncode{ - Version: 0, - SignData: make([]byte, 65), - Accounts: []types.AccountAccessListEncode{}, - }, - expectedError: true, - signFn: func(account accounts.Account, mimeType string, data []byte) ([]byte, error) { - return nil, fmt.Errorf("signing failed") - }, - description: "Should return error when signing function fails", - }, - { - name: "empty accounts list", - bal: &types.BlockAccessListEncode{ - Version: 0, - SignData: make([]byte, 65), - Accounts: []types.AccountAccessListEncode{}, - }, - expectedError: false, - signFn: mockSignFn, - description: "Should successfully sign even with empty accounts list", - }, - { - name: "multiple accounts", - bal: &types.BlockAccessListEncode{ - Version: 2, - SignData: make([]byte, 65), - Accounts: []types.AccountAccessListEncode{ - { - Address: common.HexToAddress("0x1111111111111111111111111111111111111111"), - StorageItems: []types.StorageAccessItem{ - {Key: common.HexToHash("0x01"), TxIndex: 0, Dirty: false}, - {Key: common.HexToHash("0x02"), TxIndex: 1, Dirty: true}, - }, - }, - { - Address: common.HexToAddress("0x2222222222222222222222222222222222222222"), - StorageItems: []types.StorageAccessItem{ - {Key: common.HexToHash("0x03"), TxIndex: 2, Dirty: false}, - }, - }, - }, - }, - expectedError: false, - signFn: mockSignFn, - description: "Should successfully sign with multiple accounts", - }, - } - - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - // Set up Parlia with the test signing function - parlia.signFn = tt.signFn - - // Call SignBAL - err := parlia.SignBAL(tt.bal) - - // Check results - if tt.expectedError { - if err == nil { - t.Errorf("Expected error but got none. %s", tt.description) - } - } else { - if err != nil { - t.Errorf("Expected no error but got: %v. %s", err, tt.description) - } - // Verify signature was copied to SignData - if tt.bal != nil && len(tt.bal.SignData) != 65 { - t.Errorf("Expected SignData to be 65 bytes, got %d", len(tt.bal.SignData)) - } - // Verify signature content (for successful cases) - if tt.bal != nil && !tt.expectedError { - expectedSig := "test_signature_data_for_testing_purposes_123456789012345678901234" - if string(tt.bal.SignData[:len(expectedSig)]) != expectedSig { - t.Errorf("SignData was not properly set") - } - } - } - }) - } -} - -func TestVerifyBAL(t *testing.T) { - // Setup test environment - signerKey, _ := crypto.GenerateKey() - signerAddr := crypto.PubkeyToAddress(signerKey.PublicKey) - - // Helper function to create a properly signed BAL - createBlockWithBAL := func(addr common.Address, version uint32, signLength int, accounts []types.AccountAccessListEncode) *types.Block { - header := &types.Header{ - ParentHash: types.EmptyRootHash, - Number: big.NewInt(10), - Coinbase: addr, - } - block := types.NewBlock(header, nil, nil, nil) - bal := &types.BlockAccessListEncode{ - Version: version, - Number: block.Number().Uint64(), - Hash: block.Hash(), - SignData: make([]byte, signLength), - Accounts: accounts, - } - - // RLP encode the data - data, _ := rlp.EncodeToBytes([]interface{}{bal.Version, bal.Number, bal.Hash, bal.Accounts}) - - // Create signature using the test key - hash := crypto.Keccak256(data) - sig, _ := crypto.Sign(hash, signerKey) - copy(bal.SignData, sig) - block = block.WithBAL(bal) - return block - } - - // Create a Parlia instance - parlia := &Parlia{} - - tests := []struct { - name string - block *types.Block - expectedError bool - description string - }{ - { - name: "valid signature verification", - block: createBlockWithBAL(signerAddr, 0, 65, []types.AccountAccessListEncode{ - { - Address: common.HexToAddress("0x1234567890123456789012345678901234567890"), - StorageItems: []types.StorageAccessItem{ - {Key: common.HexToHash("0x01"), TxIndex: 0, Dirty: false}, - }, - }, - }), - expectedError: false, - description: "Should successfully verify a properly signed BAL", - }, - { - name: "invalid version", - block: createBlockWithBAL(signerAddr, 1, 65, []types.AccountAccessListEncode{ - { - Address: common.HexToAddress("0x1234567890123456789012345678901234567890"), - StorageItems: []types.StorageAccessItem{ - {Key: common.HexToHash("0x01"), TxIndex: 0, Dirty: false}, - }, - }, - }), - expectedError: true, - description: "Should fail when version is invalid", - }, - { - name: "invalid signature length - too short", - block: createBlockWithBAL(signerAddr, 0, 64, []types.AccountAccessListEncode{}), - expectedError: true, - description: "Should fail when signature is too short", - }, - { - name: "invalid signature length - too long", - block: createBlockWithBAL(signerAddr, 0, 66, []types.AccountAccessListEncode{}), - expectedError: true, - description: "Should fail when signature is too long", - }, - { - name: "empty signature", - block: createBlockWithBAL(signerAddr, 0, 0, []types.AccountAccessListEncode{}), - expectedError: true, - description: "Should fail with empty signature", - }, - { - name: "signer mismatch", - block: createBlockWithBAL(common.HexToAddress("0x1234567890123456789012345678901234567890"), 0, 65, []types.AccountAccessListEncode{ - { - Address: common.HexToAddress("0x1234567890123456789012345678901234567890"), - StorageItems: []types.StorageAccessItem{ - {Key: common.HexToHash("0x01"), TxIndex: 0, Dirty: false}, - }, - }, - }), - expectedError: true, - description: "Should fail when signer address doesn't match recovered address", - }, - { - name: "empty accounts list", - block: createBlockWithBAL(signerAddr, 0, 65, []types.AccountAccessListEncode{}), - expectedError: false, - description: "Should successfully verify BAL with empty accounts", - }, - { - name: "multiple accounts", - block: createBlockWithBAL(signerAddr, 0, 65, []types.AccountAccessListEncode{ - { - Address: common.HexToAddress("0x1111111111111111111111111111111111111111"), - StorageItems: []types.StorageAccessItem{ - {Key: common.HexToHash("0x01"), TxIndex: 0, Dirty: false}, - {Key: common.HexToHash("0x02"), TxIndex: 1, Dirty: true}, - }, - }, - { - Address: common.HexToAddress("0x2222222222222222222222222222222222222222"), - StorageItems: []types.StorageAccessItem{ - {Key: common.HexToHash("0x03"), TxIndex: 2, Dirty: false}, - }, - }, - }), - expectedError: false, - description: "Should successfully verify BAL with multiple accounts", - }, - } - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - err := parlia.VerifyBAL(tt.block, tt.block.BAL()) - if tt.expectedError { - if err == nil { - t.Errorf("Expected error but got none. %s", tt.description) - } - } else { - if err != nil { - t.Errorf("Expected no error but got: %v. %s", err, tt.description) - } - } - }) - } -} - -func TestVerifyBAL_EdgeCases(t *testing.T) { - // Test with different key to ensure proper signature verification - key1, _ := crypto.GenerateKey() - key2, _ := crypto.GenerateKey() - addr1 := crypto.PubkeyToAddress(key1.PublicKey) - addr2 := crypto.PubkeyToAddress(key2.PublicKey) - - parlia := &Parlia{} - - header1 := &types.Header{ - ParentHash: types.EmptyRootHash, - Number: big.NewInt(10), - Coinbase: addr1, - } - block1 := types.NewBlock(header1, nil, nil, nil) - // Create BAL signed with key1 - bal := &types.BlockAccessListEncode{ - Version: 0, - Number: block1.Number().Uint64(), - Hash: block1.Hash(), - SignData: make([]byte, 65), - Accounts: []types.AccountAccessListEncode{ - { - Address: common.HexToAddress("0x1234567890123456789012345678901234567890"), - StorageItems: []types.StorageAccessItem{ - {Key: common.HexToHash("0x01"), TxIndex: 0, Dirty: false}, - }, - }, - }, - } - - // Sign with key1 - data, _ := rlp.EncodeToBytes([]interface{}{bal.Version, bal.Number, bal.Hash, bal.Accounts}) - hash := crypto.Keccak256(data) - sig, _ := crypto.Sign(hash, key1) - copy(bal.SignData, sig) - - // Should succeed with addr1 - err := parlia.VerifyBAL(block1, bal) - if err != nil { - t.Errorf("Verification with correct signer failed: %v", err) - } - - // Should fail with addr2 (different key) - header2 := &types.Header{ - ParentHash: types.EmptyRootHash, - Number: big.NewInt(10), - Coinbase: addr2, - } - block2 := types.NewBlock(header2, nil, nil, nil) - err = parlia.VerifyBAL(block2, bal) - if err == nil { - t.Error("Expected verification to fail with different signer address") - } -} - -func TestVerifyBAL_TooLargeData(t *testing.T) { - // Test with large amount of data to ensure RLP encoding works correctly - key, _ := crypto.GenerateKey() - addr := crypto.PubkeyToAddress(key.PublicKey) - parlia := &Parlia{} - - // Create BAL with many accounts - accounts := make([]types.AccountAccessListEncode, 20000) - for i := 0; i < 20000; i++ { - accounts[i] = types.AccountAccessListEncode{ - Address: common.BigToAddress(big.NewInt(int64(i))), - StorageItems: []types.StorageAccessItem{ - {Key: common.BigToHash(big.NewInt(int64(i))), TxIndex: uint32(i), Dirty: i%2 == 0}, - {Key: common.BigToHash(big.NewInt(int64(i + 1000))), TxIndex: uint32(i + 1), Dirty: i%3 == 0}, - }, - } - } - - header := &types.Header{ - ParentHash: types.EmptyRootHash, - Number: big.NewInt(10), - Coinbase: addr, - } - block := types.NewBlock(header, nil, nil, nil) - bal := &types.BlockAccessListEncode{ - Version: 0, - Number: block.Number().Uint64(), - Hash: block.Hash(), - SignData: make([]byte, 65), - Accounts: accounts, - } - - // Sign the large data - data, err := rlp.EncodeToBytes([]interface{}{bal.Version, bal.Number, bal.Hash, bal.Accounts}) - if err != nil { - t.Fatalf("Failed to RLP encode large data: %v", err) - } - - hash := crypto.Keccak256(data) - sig, err := crypto.Sign(hash, key) - if err != nil { - t.Fatalf("Failed to sign large data: %v", err) - } - copy(bal.SignData, sig) - - // Verify the signature - err = parlia.VerifyBAL(block, bal) - if err.Error() != "data is too large" { - t.Errorf("Failed to verify BAL with large data: %v", err) - } -} - -func TestSignBAL_VerifyBAL_Integration(t *testing.T) { - // Test complete sign-verify cycle - key, _ := crypto.GenerateKey() - addr := crypto.PubkeyToAddress(key.PublicKey) - - // Create mock signing function - mockSignFn := func(account accounts.Account, mimeType string, data []byte) ([]byte, error) { - if account.Address != addr { - return nil, fmt.Errorf("wrong address") - } - if mimeType != accounts.MimetypeParlia { - return nil, fmt.Errorf("wrong mime type") - } - // Use the actual private key to sign - hash := crypto.Keccak256(data) - return crypto.Sign(hash, key) - } - - parlia := &Parlia{ - val: addr, - signFn: mockSignFn, - } - - testCases := []struct { - name string - version uint32 - accounts []types.AccountAccessListEncode - }{ - { - name: "empty accounts", - version: 0, - accounts: []types.AccountAccessListEncode{}, - }, - { - name: "single account", - version: 0, - accounts: []types.AccountAccessListEncode{ - { - Address: common.HexToAddress("0x1234567890123456789012345678901234567890"), - StorageItems: []types.StorageAccessItem{ - {Key: common.HexToHash("0x01"), TxIndex: 0, Dirty: false}, - {Key: common.HexToHash("0x02"), TxIndex: 1, Dirty: true}, - }, - }, - }, - }, - { - name: "multiple accounts", - version: 0, - accounts: []types.AccountAccessListEncode{ - { - Address: common.HexToAddress("0x1111111111111111111111111111111111111111"), - StorageItems: []types.StorageAccessItem{ - {Key: common.HexToHash("0x01"), TxIndex: 0, Dirty: false}, - }, - }, - { - Address: common.HexToAddress("0x2222222222222222222222222222222222222222"), - StorageItems: []types.StorageAccessItem{ - {Key: common.HexToHash("0x02"), TxIndex: 1, Dirty: true}, - {Key: common.HexToHash("0x03"), TxIndex: 2, Dirty: false}, - }, - }, - }, - }, - } - - for _, tc := range testCases { - t.Run(tc.name, func(t *testing.T) { - header := &types.Header{ - ParentHash: types.EmptyRootHash, - Number: big.NewInt(10), - Coinbase: addr, - } - block := types.NewBlock(header, nil, nil, nil) - // Create BAL - bal := &types.BlockAccessListEncode{ - Version: tc.version, - Number: block.Number().Uint64(), - Hash: block.Hash(), - SignData: make([]byte, 65), - Accounts: tc.accounts, - } - - // Sign the BAL - err := parlia.SignBAL(bal) - if err != nil { - t.Fatalf("SignBAL failed: %v", err) - } - - // Verify signature length - if len(bal.SignData) != 65 { - t.Errorf("Expected SignData to be 65 bytes, got %d", len(bal.SignData)) - } - - // Verify the BAL with correct signer - err = parlia.VerifyBAL(block, bal) - if err != nil { - t.Errorf("VerifyBAL failed with correct signer: %v", err) - } - }) - } -} diff --git a/consensus/parlia/ramanujanfork.go b/consensus/parlia/ramanujanfork.go index 53473e0350..43142962d6 100644 --- a/consensus/parlia/ramanujanfork.go +++ b/consensus/parlia/ramanujanfork.go @@ -31,7 +31,7 @@ func (p *Parlia) delayForRamanujanFork(snap *Snapshot, header *types.Header) tim func (p *Parlia) blockTimeForRamanujanFork(snap *Snapshot, header, parent *types.Header) uint64 { blockTime := parent.MilliTimestamp() + snap.BlockInterval if p.chainConfig.IsRamanujan(header.Number) { - blockTime = blockTime + p.backOffTime(snap, parent, header, p.val) + blockTime = blockTime + p.backOffTime(snap, parent, header, header.Coinbase) } if now := uint64(time.Now().UnixMilli()); blockTime < now { // Just to make the millisecond part of the time look more aligned. diff --git a/core/blockchain.go b/core/blockchain.go index a2f519d0d0..aa21ae1834 100644 --- a/core/blockchain.go +++ b/core/blockchain.go @@ -18,6 +18,7 @@ package core import ( + "context" "errors" "fmt" "io" @@ -184,7 +185,6 @@ type BlockChainConfig struct { TriesInMemory uint64 // How many tries keeps in memory NoTries bool // Insecure settings. Do not have any tries in databases if enabled. PathSyncFlush bool // Whether sync flush the trienodebuffer of pathdb to disk. - JournalFilePath string // The path to store journal file which is used in pathdb EnableIncr bool // Flag whether the freezer db stores incremental block and state history IncrHistoryPath string // The path to store incremental block and chain files IncrHistory uint64 // Amount of block and state history stored in incremental freezer db @@ -234,6 +234,15 @@ type BlockChainConfig struct { // EnableBAL enables the block access list feature EnableBAL bool + + // SlowBlockThreshold is the block execution time threshold beyond which + // detailed statistics will be logged. Negative value means disabled (default), + // zero logs all blocks, positive value filters blocks by execution time. + SlowBlockThreshold time.Duration + + // Execution configs + StatelessSelfValidation bool // Generate execution witnesses and self-check against them (testing purpose) + EnableWitnessStats bool // Whether trie access statistics collection is enabled } // DefaultConfig returns the default config. @@ -286,7 +295,6 @@ func (cfg *BlockChainConfig) triedbConfig(isVerkle bool) *triedb.Config { } if cfg.StateScheme == rawdb.PathScheme { config.PathDB = &pathdb.Config{ - JournalFilePath: cfg.JournalFilePath, EnableIncr: cfg.EnableIncr, IncrHistoryPath: cfg.IncrHistoryPath, IncrHistory: cfg.IncrHistory, @@ -1316,7 +1324,6 @@ func (bc *BlockChain) setHeadBeyondRoot(head uint64, time uint64, root common.Ha rawdb.DeleteReceipts(db, hash, num) rawdb.DeleteTd(db, hash, num) rawdb.DeleteBlobSidecars(db, hash, num) - rawdb.DeleteBAL(db, hash, num) } // Todo(rjl493456442) txlookup, log index, etc } @@ -1825,7 +1832,6 @@ func (bc *BlockChain) InsertReceiptChain(blockChain types.Blocks, receiptChain [ if bc.chainConfig.IsCancun(block.Number(), block.Time()) { rawdb.WriteBlobSidecars(batch, block.Hash(), block.NumberU64(), block.Sidecars()) } - rawdb.WriteBAL(batch, block.Hash(), block.NumberU64(), block.BAL()) // Write everything belongs to the blocks into the database. So that // we can ensure all components of body is completed(body, receipts) @@ -1904,7 +1910,6 @@ func (bc *BlockChain) writeBlockWithoutState(block *types.Block, td *big.Int) (e if bc.chainConfig.IsCancun(block.Number(), block.Time()) { rawdb.WriteBlobSidecars(blockBatch, block.Hash(), block.NumberU64(), block.Sidecars()) } - rawdb.WriteBAL(blockBatch, block.Hash(), block.NumberU64(), block.BAL()) if err := blockBatch.Write(); err != nil { log.Crit("Failed to write block into disk", "err", err) } @@ -1951,12 +1956,7 @@ func (bc *BlockChain) writeBlockWithState(block *types.Block, receipts []*types. if bc.chainConfig.IsCancun(block.Number(), block.Time()) { rawdb.WriteBlobSidecars(blockBatch, block.Hash(), block.NumberU64(), block.Sidecars()) } - rawdb.WriteBAL(blockBatch, block.Hash(), block.NumberU64(), block.BAL()) - if bc.db.HasSeparateStateStore() { - rawdb.WritePreimages(bc.db.GetStateStore(), statedb.Preimages()) - } else { - rawdb.WritePreimages(blockBatch, statedb.Preimages()) - } + rawdb.WritePreimages(blockBatch, statedb.Preimages()) if err := blockBatch.Write(); err != nil { log.Crit("Failed to write block into disk", "err", err) } @@ -2406,7 +2406,15 @@ func (bc *BlockChain) insertChain(chain types.Blocks, setHead bool, makeWitness bc.updateHighestVerifiedHeader(block.Header()) // The traced section of block import. start := time.Now() - res, err := bc.ProcessBlock(parent.Root, block, setHead, makeWitness && len(chain) == 1) + config := ExecuteConfig{ + WriteState: true, + WriteHead: setHead, + EnableTracer: true, + MakeWitness: makeWitness && len(chain) == 1, + StatelessSelfValidation: bc.cfg.StatelessSelfValidation, + EnableWitnessStats: bc.cfg.EnableWitnessStats, + } + res, err := bc.ProcessBlock(context.Background(), parent.Root, block, config) if err != nil { return nil, it.index, err } @@ -2509,9 +2517,36 @@ func (bpr *blockProcessingResult) Witness() *stateless.Witness { return bpr.witness } +// ExecuteConfig defines optional behaviors during execution. +type ExecuteConfig struct { + // WriteState controls whether the computed state changes are persisted to + // the underlying storage. If false, execution is performed in-memory only. + WriteState bool + + // WriteHead indicates whether the execution result should update the canonical + // chain head. It's only relevant with WriteState == True. + WriteHead bool + + // EnableTracer enables execution tracing. This is typically used for debugging + // or analysis and may significantly impact performance. + EnableTracer bool + + // MakeWitness indicates whether to generate execution witness data during + // execution. Enabling this may introduce additional memory and CPU overhead. + MakeWitness bool + + // StatelessSelfValidation indicates whether the execution witnesses generation + // and self-validation (testing purpose) is enabled. + StatelessSelfValidation bool + + // EnableWitnessStats indicates whether to enable collection of witness trie + // access statistics + EnableWitnessStats bool +} + // ProcessBlock executes and validates the given block. If there was no error // it writes the block and associated state to database. -func (bc *BlockChain) ProcessBlock(parentRoot common.Hash, block *types.Block, setHead bool, makeWitness bool) (_ *blockProcessingResult, blockEndErr error) { +func (bc *BlockChain) ProcessBlock(ctx context.Context, parentRoot common.Hash, block *types.Block, config ExecuteConfig) (result *blockProcessingResult, blockEndErr error) { var ( err error startTime = time.Now() @@ -2521,7 +2556,7 @@ func (bc *BlockChain) ProcessBlock(parentRoot common.Hash, block *types.Block, s defer interrupt.Store(true) // terminate the prefetch at the end needBadSharedStorage := bc.chainConfig.NeedBadSharedStorage(block.Number()) - needPrefetch := needBadSharedStorage || (!bc.cfg.NoPrefetch && len(block.Transactions()) >= prefetchTxNumber) || block.BAL() != nil + needPrefetch := needBadSharedStorage || (!bc.cfg.NoPrefetch && len(block.Transactions()) >= prefetchTxNumber) if !needPrefetch { statedb, err = state.New(parentRoot, bc.statedb) if err != nil { @@ -2559,17 +2594,11 @@ func (bc *BlockChain) ProcessBlock(parentRoot common.Hash, block *types.Block, s storageCacheMissMeter.Mark(stats.StorageMiss) }() - interruptChan := make(chan struct{}) - defer close(interruptChan) go func(start time.Time, throwaway *state.StateDB, block *types.Block) { // Disable tracing for prefetcher executions. vmCfg := bc.cfg.VmConfig vmCfg.Tracer = nil - if block.BAL() != nil { - bc.prefetcher.PrefetchBAL(block, throwaway, interruptChan) - } else { - bc.prefetcher.Prefetch(block.Transactions(), block.Header(), block.GasLimit(), throwaway, vmCfg, &interrupt) - } + bc.prefetcher.Prefetch(block.Transactions(), block.Header(), block.GasLimit(), throwaway, vmCfg, &interrupt) blockPrefetchExecuteTimer.Update(time.Since(start)) if interrupt.Load() { @@ -2589,12 +2618,12 @@ func (bc *BlockChain) ProcessBlock(parentRoot common.Hash, block *types.Block, s // Generate witnesses either if we're self-testing, or if it's the // only block being inserted. A bit crude, but witnesses are huge, // so we refuse to make an entire chain of them. - if bc.cfg.VmConfig.StatelessSelfValidation || makeWitness { + if config.StatelessSelfValidation || config.MakeWitness { witness, err = stateless.NewWitness(block.Header(), bc) if err != nil { return nil, err } - if bc.cfg.VmConfig.EnableWitnessStats { + if config.EnableWitnessStats { witnessStats = stateless.NewWitnessStats() } } @@ -2602,19 +2631,22 @@ func (bc *BlockChain) ProcessBlock(parentRoot common.Hash, block *types.Block, s defer statedb.StopPrefetcher() } - if bc.logger != nil && bc.logger.OnBlockStart != nil { - td := bc.GetTd(block.ParentHash(), block.NumberU64()-1) - bc.logger.OnBlockStart(tracing.BlockEvent{ - Block: block, - TD: td, - Finalized: bc.CurrentFinalBlock(), - Safe: bc.CurrentSafeBlock(), - }) - } - if bc.logger != nil && bc.logger.OnBlockEnd != nil { - defer func() { - bc.logger.OnBlockEnd(blockEndErr) - }() + // Instrument the blockchain tracing + if config.EnableTracer { + if bc.logger != nil && bc.logger.OnBlockStart != nil { + td := bc.GetTd(block.ParentHash(), block.NumberU64()-1) + bc.logger.OnBlockStart(tracing.BlockEvent{ + Block: block, + TD: td, + Finalized: bc.CurrentFinalBlock(), + Safe: bc.CurrentSafeBlock(), + }) + } + if bc.logger != nil && bc.logger.OnBlockEnd != nil { + defer func() { + bc.logger.OnBlockEnd(blockEndErr) + }() + } } // Process block using the parent state as reference point @@ -2642,7 +2674,7 @@ func (bc *BlockChain) ProcessBlock(parentRoot common.Hash, block *types.Block, s // witness builder/runner, which would otherwise be impossible due to the // various invalid chain states/behaviors being contained in those tests. xvstart := time.Now() - if witness := statedb.Witness(); witness != nil && bc.cfg.VmConfig.StatelessSelfValidation { + if witness := statedb.Witness(); witness != nil && config.StatelessSelfValidation { log.Warn("Running stateless self-validation", "block", block.Number(), "hash", block.Hash()) // Remove critical computed fields from the block to force true recalculation @@ -2687,30 +2719,29 @@ func (bc *BlockChain) ProcessBlock(parentRoot common.Hash, block *types.Block, s blockCrossValidationTimer.Update(xvtime) // The time spent on stateless cross validation // Write the block to the chain and get the status. - var ( - wstart = time.Now() - status WriteStatus - ) - if !setHead { - // Don't set the head, only insert the block - err = bc.writeBlockWithState(block, res.Receipts, statedb) - } else { - status, err = bc.writeBlockAndSetHead(block, res.Receipts, res.Logs, statedb, nil) - } - if err != nil { - return nil, err + var status WriteStatus + if config.WriteState { + wstart := time.Now() + if !config.WriteHead { + // Don't set the head, only insert the block + err = bc.writeBlockWithState(block, res.Receipts, statedb) + } else { + status, err = bc.writeBlockAndSetHead(block, res.Receipts, res.Logs, statedb, nil) + } + if err != nil { + return nil, err + } + // Update the metrics touched during block commit + accountCommitTimer.Update(statedb.AccountCommits) + storageCommitTimer.Update(statedb.StorageCommits) + snapshotCommitTimer.Update(statedb.SnapshotCommits) + triedbCommitTimer.Update(statedb.TrieDBCommits) + blockWriteTimer.Update(time.Since(wstart) - max(statedb.AccountCommits, statedb.StorageCommits) /* concurrent */ - statedb.SnapshotCommits - statedb.TrieDBCommits) } // Report the collected witness statistics if witnessStats != nil { witnessStats.ReportMetrics(block.NumberU64()) } - - // Update the metrics touched during block commit - accountCommitTimer.Update(statedb.AccountCommits) // Account commits are complete, we can mark them - storageCommitTimer.Update(statedb.StorageCommits) // Storage commits are complete, we can mark them - snapshotCommitTimer.Update(statedb.SnapshotCommits) // Snapshot commits are complete, we can mark them - triedbCommitTimer.Update(statedb.TrieDBCommits) // Trie database commits are complete, we can mark them - blockWriteTimer.Update(time.Since(wstart) - max(statedb.AccountCommits, statedb.StorageCommits) /* concurrent */ - statedb.SnapshotCommits - statedb.TrieDBCommits) elapsed := time.Since(startTime) + 1 // prevent zero division blockInsertTimer.Update(elapsed) blockInsertTxSizeGauge.Update(int64(len(block.Transactions()))) @@ -3026,6 +3057,7 @@ func (bc *BlockChain) reorg(oldHead *types.Header, newHead *types.Header) error // as the txlookups should be changed atomically, and all subsequent // reads should be blocked until the mutation is complete. bc.txLookupLock.Lock() + defer bc.txLookupLock.Unlock() // Reorg can be executed, start reducing the chain's old blocks and appending // the new blocks @@ -3132,9 +3164,6 @@ func (bc *BlockChain) reorg(oldHead *types.Header, newHead *types.Header) error // Reset the tx lookup cache to clear stale txlookup cache. bc.txLookupCache.Purge() - // Release the tx-lookup lock after mutation. - bc.txLookupLock.Unlock() - return nil } diff --git a/core/blockchain_insert.go b/core/blockchain_insert.go index acfa58d3c6..550bd192ea 100644 --- a/core/blockchain_insert.go +++ b/core/blockchain_insert.go @@ -62,7 +62,7 @@ func (st *insertStats) report(chain []*types.Block, index int, snapDiffItems, sn context := []interface{}{ "number", end.Number(), "hash", end.Hash(), "miner", end.Coinbase(), "blocks", st.processed, "txs", txs, "blobs", blobs, "mgas", float64(st.usedGas) / 1000000, - "elapsed", common.PrettyDuration(elapsed), "mgasps", mgasps, "BAL", end.BAL() != nil, + "elapsed", common.PrettyDuration(elapsed), "mgasps", mgasps, } blockInsertMgaspsGauge.Update(int64(mgasps)) if timestamp := time.Unix(int64(end.Time()), 0); time.Since(timestamp) > time.Minute { diff --git a/core/blockchain_reader.go b/core/blockchain_reader.go index 26ae7c7b8a..72c0ab9571 100644 --- a/core/blockchain_reader.go +++ b/core/blockchain_reader.go @@ -213,10 +213,6 @@ func (bc *BlockChain) GetBlock(hash common.Hash, number uint64) *types.Block { sidecars := rawdb.ReadBlobSidecars(bc.db, hash, number) block = block.WithSidecars(sidecars) - bal := rawdb.ReadBAL(bc.db, hash, number) - if bal != nil { - block = block.WithBAL(bal) - } // Cache the found block for next time and return bc.blockCache.Add(block.Hash(), block) return block @@ -490,9 +486,6 @@ 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.statedb) - if bc.cfg.EnableBAL { - stateDb.InitBlockAccessList() - } if err != nil { return nil, err } @@ -515,9 +508,6 @@ func (bc *BlockChain) StateWithCacheAt(root common.Hash) (*state.StateDB, error) return nil, err } stateDb, err := state.NewWithReader(root, bc.statedb, process) - if bc.cfg.EnableBAL { - stateDb.InitBlockAccessList() - } if err != nil { return nil, err } diff --git a/core/error.go b/core/error.go index 43002ce40b..1446e6e28f 100644 --- a/core/error.go +++ b/core/error.go @@ -68,10 +68,6 @@ var ( // have enough funds for transfer(topmost call only). ErrInsufficientFundsForTransfer = errors.New("insufficient funds for transfer") - // ErrMaxInitCodeSizeExceeded is returned if creation transaction provides the init code bigger - // than init code size limit. - ErrMaxInitCodeSizeExceeded = errors.New("max initcode size exceeded") - // ErrInsufficientBalanceWitness is returned if the transaction sender has enough // funds to cover the transfer, but not enough to pay for witness access/modification // costs for the transaction diff --git a/core/genesis.go b/core/genesis.go index 0fbabfeeb7..d743ee863d 100644 --- a/core/genesis.go +++ b/core/genesis.go @@ -273,9 +273,9 @@ type ChainOverrides struct { OverrideFermi *uint64 OverrideOsaka *uint64 OverrideMendel *uint64 + OverridePasteur *uint64 OverrideBPO1 *uint64 OverrideBPO2 *uint64 - OverridePasteur *uint64 OverrideVerkle *uint64 } @@ -311,15 +311,15 @@ func (o *ChainOverrides) apply(cfg *params.ChainConfig) error { if o.OverrideMendel != nil { cfg.MendelTime = o.OverrideMendel } + if o.OverridePasteur != nil { + cfg.PasteurTime = o.OverridePasteur + } if o.OverrideBPO1 != nil { cfg.BPO1Time = o.OverrideBPO1 } if o.OverrideBPO2 != nil { cfg.BPO2Time = o.OverrideBPO2 } - if o.OverridePasteur != nil { - cfg.PasteurTime = o.OverridePasteur - } if o.OverrideVerkle != nil { cfg.VerkleTime = o.OverrideVerkle } diff --git a/core/rawdb/accessors_chain.go b/core/rawdb/accessors_chain.go index cf8bc994a4..e6cc71ade6 100644 --- a/core/rawdb/accessors_chain.go +++ b/core/rawdb/accessors_chain.go @@ -951,47 +951,6 @@ func DeleteBlobSidecars(db ethdb.KeyValueWriter, hash common.Hash, number uint64 } } -// ReadBALRLP retrieves all the block access list belonging to a block in RLP encoding. -func ReadBALRLP(db ethdb.Reader, hash common.Hash, number uint64) rlp.RawValue { - // BAL is only in kv DB, will not be put into ancient DB - data, _ := db.Get(blockBALKey(number, hash)) - return data -} - -// ReadBAL retrieves the block access list belonging to a block. -func ReadBAL(db ethdb.Reader, hash common.Hash, number uint64) *types.BlockAccessListEncode { - data := ReadBALRLP(db, hash, number) - if len(data) == 0 { - return nil - } - var ret types.BlockAccessListEncode - if err := rlp.DecodeBytes(data, &ret); err != nil { - log.Error("Invalid BAL RLP", "hash", hash, "err", err) - return nil - } - return &ret -} - -func WriteBAL(db ethdb.KeyValueWriter, hash common.Hash, number uint64, bal *types.BlockAccessListEncode) { - if bal == nil { - return - } - data, err := rlp.EncodeToBytes(bal) - if err != nil { - log.Crit("Failed to encode block BAL", "err", err) - } - - if err := db.Put(blockBALKey(number, hash), data); err != nil { - log.Crit("Failed to store block BAL", "err", err) - } -} - -func DeleteBAL(db ethdb.KeyValueWriter, hash common.Hash, number uint64) { - if err := db.Delete(blockBALKey(number, hash)); err != nil { - log.Crit("Failed to delete block BAL", "err", err) - } -} - // WriteAncientHeaderChain writes the supplied headers along with nil block // bodies and receipts into the ancient store. It's supposed to be used for // storing chain segment before the chain cutoff. @@ -1034,7 +993,6 @@ func DeleteBlock(db ethdb.KeyValueWriter, hash common.Hash, number uint64) { DeleteBody(db, hash, number) DeleteTd(db, hash, number) DeleteBlobSidecars(db, hash, number) // it is safe to delete non-exist blob - DeleteBAL(db, hash, number) } // DeleteBlockWithoutNumber removes all block data associated with a hash, except @@ -1045,7 +1003,6 @@ func DeleteBlockWithoutNumber(db ethdb.KeyValueWriter, hash common.Hash, number DeleteBody(db, hash, number) DeleteTd(db, hash, number) DeleteBlobSidecars(db, hash, number) - DeleteBAL(db, hash, number) } const badBlockToKeep = 10 diff --git a/core/rawdb/accessors_chain_test.go b/core/rawdb/accessors_chain_test.go index c23c338fef..7e6ec34b76 100644 --- a/core/rawdb/accessors_chain_test.go +++ b/core/rawdb/accessors_chain_test.go @@ -1122,376 +1122,3 @@ func TestHeadersRLPStorage(t *testing.T) { checkSequence(1, 1) // Only block 1 checkSequence(1, 2) // Genesis + block 1 } - -// Tests BAL (Block Access List) storage and retrieval operations. -func TestBALStorage(t *testing.T) { - db := NewMemoryDatabase() - - // Create test BAL data - bal := &types.BlockAccessListEncode{ - Version: 1, - SignData: make([]byte, 65), - Accounts: []types.AccountAccessListEncode{ - { - TxIndex: 0, - Address: common.HexToAddress("0x1234567890123456789012345678901234567890"), - StorageItems: []types.StorageAccessItem{ - {Key: common.HexToHash("0x01"), TxIndex: 0, Dirty: false}, - {Key: common.HexToHash("0x02"), TxIndex: 1, Dirty: true}, - }, - }, - { - TxIndex: 1, - Address: common.HexToAddress("0x2222222222222222222222222222222222222222"), - StorageItems: []types.StorageAccessItem{ - {Key: common.HexToHash("0x03"), TxIndex: 2, Dirty: false}, - }, - }, - }, - } - - // Fill SignData with test data - copy(bal.SignData, []byte("test_signature_data_for_bal_testing_12345678901234567890123456789")) - - hash := common.HexToHash("0x123456789abcdef") - number := uint64(42) - - // Test non-existent BAL retrieval - if entry := ReadBAL(db, hash, number); entry != nil { - t.Fatalf("Non-existent BAL returned: %v", entry) - } - if entry := ReadBALRLP(db, hash, number); len(entry) != 0 { - t.Fatalf("Non-existent raw BAL returned: %v", entry) - } - - // Test BAL storage and retrieval - WriteBAL(db, hash, number, bal) - if entry := ReadBAL(db, hash, number); entry == nil { - t.Fatalf("Stored BAL not found") - } else if !balEqual(entry, bal) { - t.Fatalf("Retrieved BAL mismatch: have %v, want %v", entry, bal) - } - - // Test raw BAL retrieval - if entry := ReadBALRLP(db, hash, number); len(entry) == 0 { - t.Fatalf("Stored raw BAL not found") - } - - // Test BAL deletion - DeleteBAL(db, hash, number) - if entry := ReadBAL(db, hash, number); entry != nil { - t.Fatalf("Deleted BAL still returned: %v", entry) - } - if entry := ReadBALRLP(db, hash, number); len(entry) != 0 { - t.Fatalf("Deleted raw BAL still returned: %v", entry) - } -} - -func TestBALRLPStorage(t *testing.T) { - db := NewMemoryDatabase() - - // Test different BAL configurations - testCases := []struct { - name string - bal *types.BlockAccessListEncode - hash common.Hash - number uint64 - }{ - { - name: "empty accounts", - bal: &types.BlockAccessListEncode{ - Version: 0, - SignData: make([]byte, 65), - Accounts: []types.AccountAccessListEncode{}, - }, - hash: common.HexToHash("0x1111"), - number: 1, - }, - { - name: "single account with multiple storage items", - bal: &types.BlockAccessListEncode{ - Version: 2, - SignData: make([]byte, 65), - Accounts: []types.AccountAccessListEncode{ - { - TxIndex: 0, - Address: common.HexToAddress("0xabcdefabcdefabcdefabcdefabcdefabcdefabcd"), - StorageItems: []types.StorageAccessItem{ - {Key: common.HexToHash("0x0a"), TxIndex: 0, Dirty: true}, - {Key: common.HexToHash("0x0b"), TxIndex: 1, Dirty: false}, - {Key: common.HexToHash("0x0c"), TxIndex: 2, Dirty: true}, - }, - }, - }, - }, - hash: common.HexToHash("0x2222"), - number: 2, - }, - { - name: "multiple accounts", - bal: &types.BlockAccessListEncode{ - Version: ^uint32(0), // Max uint32 value - SignData: make([]byte, 65), - Accounts: []types.AccountAccessListEncode{ - { - TxIndex: 0, - Address: common.HexToAddress("0x1111111111111111111111111111111111111111"), - StorageItems: []types.StorageAccessItem{ - {Key: common.HexToHash("0x01"), TxIndex: 0, Dirty: false}, - }, - }, - { - TxIndex: 1, - Address: common.HexToAddress("0x3333333333333333333333333333333333333333"), - StorageItems: []types.StorageAccessItem{ - {Key: common.HexToHash("0x04"), TxIndex: 3, Dirty: true}, - {Key: common.HexToHash("0x05"), TxIndex: 4, Dirty: false}, - }, - }, - { - TxIndex: 2, - Address: common.HexToAddress("0x4444444444444444444444444444444444444444"), - StorageItems: []types.StorageAccessItem{}, - }, - }, - }, - hash: common.HexToHash("0x3333"), - number: 100, - }, - } - - for _, tc := range testCases { - t.Run(tc.name, func(t *testing.T) { - // Fill SignData with unique test data - sigData := fmt.Sprintf("test_signature_for_%s_123456789012345678901234567890123456789012345678901234567890", tc.name) - copy(tc.bal.SignData, []byte(sigData)) - - // Store BAL - WriteBAL(db, tc.hash, tc.number, tc.bal) - - // Test RLP retrieval - rawData := ReadBALRLP(db, tc.hash, tc.number) - if len(rawData) == 0 { - t.Fatalf("Failed to store/retrieve raw BAL data") - } - - // Test structured retrieval - retrieved := ReadBAL(db, tc.hash, tc.number) - if retrieved == nil { - t.Fatalf("Failed to retrieve structured BAL") - } - - // Compare values - if !balEqual(retrieved, tc.bal) { - t.Fatalf("Retrieved BAL doesn't match stored BAL") - } - - // Test deletion - DeleteBAL(db, tc.hash, tc.number) - if ReadBAL(db, tc.hash, tc.number) != nil { - t.Fatalf("BAL not properly deleted") - } - }) - } -} - -func TestBALCorruptedData(t *testing.T) { - db := NewMemoryDatabase() - hash := common.HexToHash("0x9999") - number := uint64(123) - - // Store corrupted RLP data directly - corruptedData := []byte{0xff, 0xff, 0xff, 0xff} // Invalid RLP - if err := db.Put(blockBALKey(number, hash), corruptedData); err != nil { - t.Fatalf("Failed to store corrupted data: %v", err) - } - - // ReadBALRLP should return the corrupted data - rawData := ReadBALRLP(db, hash, number) - if !bytes.Equal(rawData, corruptedData) { - t.Fatalf("ReadBALRLP should return raw data even if corrupted") - } - - // ReadBAL should return nil for corrupted data - bal := ReadBAL(db, hash, number) - if bal != nil { - t.Fatalf("ReadBAL should return nil for corrupted data, got: %v", bal) - } -} - -func TestBALLargeData(t *testing.T) { - db := NewMemoryDatabase() - - // Create BAL with large amount of data - accounts := make([]types.AccountAccessListEncode, 1000) - for i := 0; i < 1000; i++ { - storageItems := make([]types.StorageAccessItem, 10) - for j := 0; j < 10; j++ { - storageItems[j] = types.StorageAccessItem{ - Key: common.BigToHash(big.NewInt(int64(i*10 + j))), - TxIndex: uint32(i*10 + j), - Dirty: (i+j)%2 == 0, - } - } - accounts[i] = types.AccountAccessListEncode{ - TxIndex: uint32(i), - Address: common.BigToAddress(big.NewInt(int64(i))), - StorageItems: storageItems, - } - } - - bal := &types.BlockAccessListEncode{ - Version: 12345, - SignData: make([]byte, 65), - Accounts: accounts, - } - - // Fill SignData - copy(bal.SignData, []byte("large_data_test_signature_123456789012345678901234567890123456789")) - - hash := common.HexToHash("0xaaaa") - number := uint64(999) - - // Test storage and retrieval of large data - WriteBAL(db, hash, number, bal) - - retrieved := ReadBAL(db, hash, number) - if retrieved == nil { - t.Fatalf("Failed to retrieve large BAL data") - } - - if !balEqual(retrieved, bal) { - t.Fatalf("Large BAL data integrity check failed") - } - - // Test deletion - DeleteBAL(db, hash, number) - if ReadBAL(db, hash, number) != nil { - t.Fatalf("Large BAL data not properly deleted") - } -} - -func TestBALMultipleBlocks(t *testing.T) { - db := NewMemoryDatabase() - - // Store BALs for multiple blocks - blocks := []struct { - hash common.Hash - number uint64 - bal *types.BlockAccessListEncode - }{ - { - hash: common.HexToHash("0xaaaa"), - number: 1, - bal: &types.BlockAccessListEncode{ - Version: 1, - SignData: make([]byte, 65), - Accounts: []types.AccountAccessListEncode{ - { - TxIndex: 0, - Address: common.HexToAddress("0x1111111111111111111111111111111111111111"), - StorageItems: []types.StorageAccessItem{ - {Key: common.HexToHash("0x01"), TxIndex: 0, Dirty: false}, - }, - }, - }, - }, - }, - { - hash: common.HexToHash("0xbbbb"), - number: 2, - bal: &types.BlockAccessListEncode{ - Version: 2, - SignData: make([]byte, 65), - Accounts: []types.AccountAccessListEncode{ - { - TxIndex: 0, - Address: common.HexToAddress("0x2222222222222222222222222222222222222222"), - StorageItems: []types.StorageAccessItem{ - {Key: common.HexToHash("0x02"), TxIndex: 1, Dirty: true}, - }, - }, - }, - }, - }, - { - hash: common.HexToHash("0xcccc"), - number: 3, - bal: &types.BlockAccessListEncode{ - Version: 3, - SignData: make([]byte, 65), - Accounts: []types.AccountAccessListEncode{}, - }, - }, - } - - // Store all BALs - for i, block := range blocks { - sigData := fmt.Sprintf("signature_for_block_%d_123456789012345678901234567890123456789012345678901234567890", i) - copy(block.bal.SignData, []byte(sigData)) - WriteBAL(db, block.hash, block.number, block.bal) - } - - // Verify all can be retrieved independently - for i, block := range blocks { - retrieved := ReadBAL(db, block.hash, block.number) - if retrieved == nil { - t.Fatalf("Failed to retrieve BAL for block %d", i) - } - if !balEqual(retrieved, block.bal) { - t.Fatalf("BAL mismatch for block %d", i) - } - } - - // Delete middle block - DeleteBAL(db, blocks[1].hash, blocks[1].number) - - // Verify first and third blocks still exist - if ReadBAL(db, blocks[0].hash, blocks[0].number) == nil { - t.Fatalf("Block 0 BAL was incorrectly deleted") - } - if ReadBAL(db, blocks[1].hash, blocks[1].number) != nil { - t.Fatalf("Block 1 BAL was not deleted") - } - if ReadBAL(db, blocks[2].hash, blocks[2].number) == nil { - t.Fatalf("Block 2 BAL was incorrectly deleted") - } -} - -// Helper function to compare two BlockAccessListEncode structs -func balEqual(a, b *types.BlockAccessListEncode) bool { - if a == nil && b == nil { - return true - } - if a == nil || b == nil { - return false - } - if a.Version != b.Version { - return false - } - if !bytes.Equal(a.SignData, b.SignData) { - return false - } - if len(a.Accounts) != len(b.Accounts) { - return false - } - for i, accountA := range a.Accounts { - accountB := b.Accounts[i] - if accountA.TxIndex != accountB.TxIndex { - return false - } - if accountA.Address != accountB.Address { - return false - } - if len(accountA.StorageItems) != len(accountB.StorageItems) { - return false - } - for j, storageA := range accountA.StorageItems { - storageB := accountB.StorageItems[j] - if storageA.Key != storageB.Key || storageA.TxIndex != storageB.TxIndex || storageA.Dirty != storageB.Dirty { - return false - } - } - } - return true -} diff --git a/core/rawdb/accessors_trie.go b/core/rawdb/accessors_trie.go index c0fb62b9ac..ce1a0b2c41 100644 --- a/core/rawdb/accessors_trie.go +++ b/core/rawdb/accessors_trie.go @@ -243,12 +243,12 @@ func DeleteTrieNode(db ethdb.KeyValueWriter, owner common.Hash, path []byte, has // if the state is not present in database. func ReadStateScheme(db ethdb.Database) string { // Check if state in path-based scheme is present. - if HasAccountTrieNode(db.StateStoreReader(), nil) { + if HasAccountTrieNode(db, nil) { return PathScheme } // The root node might be deleted during the initial snap sync, check // the persistent state id then. - if id := ReadPersistentStateID(db.StateStoreReader()); id != 0 { + if id := ReadPersistentStateID(db); id != 0 { return PathScheme } // Check if verkle state in path-based scheme is present. @@ -268,7 +268,7 @@ func ReadStateScheme(db ethdb.Database) string { if header == nil { return "" // empty datadir } - if !HasLegacyTrieNode(db.StateStoreReader(), header.Root) { + if !HasLegacyTrieNode(db, header.Root) { return "" // no state in disk } return HashScheme diff --git a/core/rawdb/ancient_utils.go b/core/rawdb/ancient_utils.go index d1db8401cb..216eda4b8d 100644 --- a/core/rawdb/ancient_utils.go +++ b/core/rawdb/ancient_utils.go @@ -91,9 +91,6 @@ func inspectFreezers(db ethdb.Database) ([]freezerInfo, error) { infos = append(infos, info) case MerkleStateFreezerName, VerkleStateFreezerName: - if db.HasSeparateStateStore() { - continue - } datadir, err := db.AncientDatadir() if err != nil { return nil, err @@ -177,7 +174,7 @@ func inspectIncrFreezers(db *snapDBWrapper) ([]freezerInfo, error) { // ancient indicates the path of root ancient directory where the chain freezer can // be opened. Start and end specify the range for dumping out indexes. // Note this function can only be used for debugging purposes. -func InspectFreezerTable(ancient string, freezerName string, tableName string, start, end int64, multiDatabase bool) error { +func InspectFreezerTable(ancient string, freezerName string, tableName string, start, end int64) error { var ( path string tables map[string]freezerTableConfig @@ -187,11 +184,7 @@ func InspectFreezerTable(ancient string, freezerName string, tableName string, s path, tables = resolveChainFreezerDir(ancient), chainFreezerTableConfigs case MerkleStateFreezerName, VerkleStateFreezerName: - if multiDatabase { - path, tables = filepath.Join(filepath.Dir(ancient)+"/state/ancient", freezerName), stateFreezerTableConfigs - } else { - path, tables = filepath.Join(ancient, freezerName), stateFreezerTableConfigs - } + path, tables = filepath.Join(ancient, freezerName), stateFreezerTableConfigs default: return fmt.Errorf("unknown freezer, supported ones: %v", freezers) } diff --git a/core/rawdb/database.go b/core/rawdb/database.go index 3b4abf71b7..8ba416d560 100644 --- a/core/rawdb/database.go +++ b/core/rawdb/database.go @@ -49,15 +49,6 @@ type freezerdb struct { readOnly bool ancientRoot string - - stateStore ethdb.Database -} - -func (frdb *freezerdb) StateStoreReader() ethdb.Reader { - if frdb.stateStore == nil { - return frdb - } - return frdb.stateStore } // AncientDatadir returns the path of root ancient directory. @@ -75,35 +66,12 @@ func (frdb *freezerdb) Close() error { if err := frdb.KeyValueStore.Close(); err != nil { errs = append(errs, err) } - if frdb.HasSeparateStateStore() { - if err := frdb.GetStateStore().Close(); err != nil { - errs = append(errs, err) - } - } if len(errs) != 0 { return fmt.Errorf("%v", errs) } return nil } -func (frdb *freezerdb) SetStateStore(state ethdb.Database) { - if frdb.stateStore != nil { - frdb.stateStore.Close() - } - frdb.stateStore = state -} - -func (frdb *freezerdb) GetStateStore() ethdb.Database { - if frdb.stateStore != nil { - return frdb.stateStore - } - return frdb -} - -func (frdb *freezerdb) HasSeparateStateStore() bool { - return frdb.stateStore != nil -} - // Freeze is a helper method used for external testing to trigger and block until // a freeze cycle completes, without having to sleep for a minute to trigger the // automatic background run. @@ -130,7 +98,6 @@ func (frdb *freezerdb) SetupFreezerEnv(env *ethdb.FreezerEnv, blockHistory uint6 // nofreezedb is a database wrapper that disables freezer data retrievals. type nofreezedb struct { ethdb.KeyValueStore - stateStore ethdb.Database } // Ancient returns an error as we don't have a backing chain freezer. @@ -198,28 +165,6 @@ func (db *nofreezedb) SyncAncient() error { return errNotSupported } -func (db *nofreezedb) SetStateStore(state ethdb.Database) { - db.stateStore = state -} - -func (db *nofreezedb) GetStateStore() ethdb.Database { - if db.stateStore != nil { - return db.stateStore - } - return db -} - -func (db *nofreezedb) HasSeparateStateStore() bool { - return db.stateStore != nil -} - -func (db *nofreezedb) StateStoreReader() ethdb.Reader { - if db.stateStore != nil { - return db.stateStore - } - return db -} - func (db *nofreezedb) ReadAncients(fn func(reader ethdb.AncientReaderOp) error) (err error) { // Unlike other ancient-related methods, this method does not return // errNotSupported when invoked. @@ -321,10 +266,6 @@ func (db *emptyfreezedb) SyncAncient() error { return nil } -func (db *emptyfreezedb) GetStateStore() ethdb.Database { return db } -func (db *emptyfreezedb) SetStateStore(state ethdb.Database) {} -func (db *emptyfreezedb) StateStoreReader() ethdb.Reader { return db } -func (db *emptyfreezedb) HasSeparateStateStore() bool { return false } func (db *emptyfreezedb) ReadAncients(fn func(reader ethdb.AncientReaderOp) error) (err error) { return nil } @@ -623,43 +564,9 @@ func AncientInspect(db ethdb.Database) error { return nil } -type DataType int - -const ( - StateDataType DataType = iota - ChainDataType - Unknown -) - -func DataTypeByKey(key []byte) DataType { - switch { - // state - case IsLegacyTrieNode(key, key), - bytes.HasPrefix(key, stateIDPrefix) && len(key) == len(stateIDPrefix)+common.HashLength, - IsAccountTrieNode(key), - IsStorageTrieNode(key): - return StateDataType - - default: - for _, meta := range [][]byte{ - fastTrieProgressKey, persistentStateIDKey, trieJournalKey, snapSyncStatusFlagKey} { - if bytes.Equal(key, meta) { - return StateDataType - } - } - return ChainDataType - } -} - // InspectDatabase traverses the entire database and checks the size // of all different categories of data. func InspectDatabase(db ethdb.Database, keyPrefix, keyStart []byte) error { - var trieIter ethdb.Iterator - if db.HasSeparateStateStore() { - trieIter = db.GetStateStore().NewIterator(keyPrefix, nil) - defer trieIter.Release() - } - var ( start = time.Now() count atomic.Int64 @@ -672,7 +579,6 @@ func InspectDatabase(db ethdb.Database, keyPrefix, keyStart []byte) error { tds stat numHashPairings stat blobSidecars stat - bals stat hashNumPairings stat legacyTries stat stateLookups stat @@ -812,8 +718,6 @@ func InspectDatabase(db ethdb.Database, keyPrefix, keyStart []byte) error { // bsc speicial case bytes.HasPrefix(key, BlockBlobSidecarsPrefix): blobSidecars.add(size) - case bytes.HasPrefix(key, BlockBALPrefix): - bals.add(size) case bytes.HasPrefix(key, ParliaSnapshotPrefix) && len(key) == 7+common.HashLength: parliaSnaps.add(size) @@ -839,50 +743,6 @@ func InspectDatabase(db ethdb.Database, keyPrefix, keyStart []byte) error { return it.Error() } - // inspect separate trie db - if trieIter != nil { - count.Store(0) - logged := time.Now() - for trieIter.Next() { - var ( - key = trieIter.Key() - value = trieIter.Value() - size = common.StorageSize(len(key) + len(value)) - ) - total.Add(uint64(size)) - - switch { - case IsLegacyTrieNode(key, value): - legacyTries.add(size) - case bytes.HasPrefix(key, stateIDPrefix) && len(key) == len(stateIDPrefix)+common.HashLength: - stateLookups.add(size) - case IsAccountTrieNode(key): - accountTries.add(size) - case IsStorageTrieNode(key): - storageTries.add(size) - default: - var accounted bool - for _, meta := range [][]byte{ - fastTrieProgressKey, persistentStateIDKey, trieJournalKey, snapSyncStatusFlagKey} { - if bytes.Equal(key, meta) { - metadata.add(size) - accounted = true - break - } - } - if !accounted { - unaccounted.add(size) - } - } - count.Add(1) - if count.Load()%1000 == 0 && time.Since(logged) > 8*time.Second { - log.Info("Inspecting separate state database", "count", count.Load(), "elapsed", common.PrettyDuration(time.Since(start))) - logged = time.Now() - } - } - log.Info("Inspecting separate state database", "count", count.Load(), "elapsed", common.PrettyDuration(time.Since(start))) - } - var ( eg, ctx = errgroup.WithContext(context.Background()) workers = runtime.NumCPU() @@ -944,7 +804,6 @@ func InspectDatabase(db ethdb.Database, keyPrefix, keyStart []byte) error { {"Key-Value store", "Singleton metadata", metadata.sizeString(), metadata.countString()}, // bsc special {"Key-Value store", "BlobSidecars", blobSidecars.sizeString(), blobSidecars.countString()}, - {"Key-Value store", "Block access list", bals.sizeString(), bals.countString()}, {"Key-Value store", "Parlia snapshots", parliaSnaps.sizeString(), parliaSnaps.countString()}, } @@ -965,27 +824,6 @@ func InspectDatabase(db ethdb.Database, keyPrefix, keyStart []byte) error { total.Add(uint64(ancient.size())) } - // inspect ancient state in separate trie db if exist - if trieIter != nil { - stateAncients, err := inspectFreezers(db.GetStateStore()) - if err != nil { - return err - } - for _, ancient := range stateAncients { - for _, table := range ancient.sizes { - if ancient.name == "chain" { - break - } - stats = append(stats, []string{ - fmt.Sprintf("Ancient store (%s)", strings.Title(ancient.name)), - strings.Title(table.name), - table.size.String(), - fmt.Sprintf("%d", ancient.count()), - }) - } - total.Add(uint64(ancient.size())) - } - } table := newTableWriter(os.Stdout) table.SetHeader([]string{"Database", "Category", "Size", "Items"}) table.SetFooter([]string{"", "Total", common.StorageSize(total.Load()).String(), fmt.Sprintf("%d", count.Load())}) diff --git a/core/rawdb/freezer_table.go b/core/rawdb/freezer_table.go index 6b2d4c2c27..d5d856d71c 100644 --- a/core/rawdb/freezer_table.go +++ b/core/rawdb/freezer_table.go @@ -167,6 +167,7 @@ func newTable(path string, name string, readMeter, writeMeter *metrics.Meter, si // the initialization. meta, err = openFreezerFileForAppend(filepath.Join(path, fmt.Sprintf("%s.meta", name))) if err != nil { + index.Close() return nil, err } } else { @@ -176,6 +177,7 @@ func newTable(path string, name string, readMeter, writeMeter *metrics.Meter, si } meta, err = openFreezerFileForAppend(filepath.Join(path, fmt.Sprintf("%s.meta", name))) if err != nil { + index.Close() return nil, err } } @@ -183,6 +185,8 @@ func newTable(path string, name string, readMeter, writeMeter *metrics.Meter, si // is detected. metadata, err := newMetadata(meta) if err != nil { + meta.Close() + index.Close() return nil, err } // Create the table and repair any past inconsistency diff --git a/core/rawdb/freezer_utils.go b/core/rawdb/freezer_utils.go index 752e95ba6a..2088b39617 100644 --- a/core/rawdb/freezer_utils.go +++ b/core/rawdb/freezer_utils.go @@ -69,6 +69,11 @@ func copyFrom(srcPath, destPath string, offset uint64, before func(f *os.File) e // we do the final move. src.Close() + // Permanently persist the content into disk + if err := f.Sync(); err != nil { + return err + } + if err := f.Close(); err != nil { return err } @@ -87,6 +92,7 @@ func openFreezerFileForAppend(filename string) (*os.File, error) { } // Seek to end for append if _, err = file.Seek(0, io.SeekEnd); err != nil { + file.Close() return nil, err } return file, nil diff --git a/core/rawdb/schema.go b/core/rawdb/schema.go index 5df4fbccb3..6b5d83be46 100644 --- a/core/rawdb/schema.go +++ b/core/rawdb/schema.go @@ -149,8 +149,6 @@ var ( BlockBlobSidecarsPrefix = []byte("blobs") - BlockBALPrefix = []byte("bal") // blockBALPrefix + blockNumber (uint64 big endian) + blockHash -> block access list - // new log index filterMapsPrefix = "fm-" filterMapsRangeKey = []byte(filterMapsPrefix + "R") @@ -224,11 +222,6 @@ func blockBlobSidecarsKey(number uint64, hash common.Hash) []byte { return append(append(BlockBlobSidecarsPrefix, encodeBlockNumber(number)...), hash.Bytes()...) } -// blockBALKey = blockBALPrefix + blockNumber (uint64 big endian) + blockHash -func blockBALKey(number uint64, hash common.Hash) []byte { - return append(append(BlockBALPrefix, encodeBlockNumber(number)...), hash.Bytes()...) -} - // txLookupKey = txLookupPrefix + hash func txLookupKey(hash common.Hash) []byte { return append(txLookupPrefix, hash.Bytes()...) diff --git a/core/rawdb/table.go b/core/rawdb/table.go index d26166031e..98fc2736d7 100644 --- a/core/rawdb/table.go +++ b/core/rawdb/table.go @@ -220,22 +220,6 @@ func (t *table) NewBatch() ethdb.Batch { return &tableBatch{t.db.NewBatch(), t.prefix} } -func (t *table) SetStateStore(state ethdb.Database) { - panic("not implement") -} - -func (t *table) GetStateStore() ethdb.Database { - return nil -} - -func (t *table) HasSeparateStateStore() bool { - return false -} - -func (t *table) StateStoreReader() ethdb.Reader { - return nil -} - // NewBatchWithSize creates a write-only database batch with pre-allocated buffer. func (t *table) NewBatchWithSize(size int) ethdb.Batch { return &tableBatch{t.db.NewBatchWithSize(size), t.prefix} diff --git a/core/state/pruner/pruner.go b/core/state/pruner/pruner.go index e6a64f2413..58c777dbee 100644 --- a/core/state/pruner/pruner.go +++ b/core/state/pruner/pruner.go @@ -127,19 +127,13 @@ func prune(snaptree *snapshot.Tree, root common.Hash, maindb ethdb.Database, sta // that the false-positive is low enough(~0.05%). The probability of the // dangling node is the state root is super low. So the dangling nodes in // theory will never ever be visited again. - var pruneDB ethdb.Database - if maindb != nil && maindb.HasSeparateStateStore() { - pruneDB = maindb.GetStateStore() - } else { - pruneDB = maindb - } var ( skipped, count int size common.StorageSize pstart = time.Now() logged = time.Now() - batch = pruneDB.NewBatch() - iter = pruneDB.NewIterator(nil, nil) + batch = maindb.NewBatch() + iter = maindb.NewIterator(nil, nil) ) for iter.Next() { key := iter.Key() @@ -183,7 +177,7 @@ func prune(snaptree *snapshot.Tree, root common.Hash, maindb ethdb.Database, sta batch.Reset() iter.Release() - iter = pruneDB.NewIterator(nil, key) + iter = maindb.NewIterator(nil, key) } } } @@ -228,7 +222,7 @@ func prune(snaptree *snapshot.Tree, root common.Hash, maindb ethdb.Database, sta end = nil } log.Info("Compacting database", "range", fmt.Sprintf("%#x-%#x", start, end), "elapsed", common.PrettyDuration(time.Since(cstart))) - if err := pruneDB.Compact(start, end); err != nil { + if err := maindb.Compact(start, end); err != nil { log.Error("Database compaction failed", "error", err) return err } @@ -273,17 +267,10 @@ func (p *Pruner) Prune(root common.Hash) error { // Use the bottom-most diff layer as the target root = layers[len(layers)-1].Root() } - // if the separated state db has been set, use this db to prune data - var trienodedb ethdb.Database - if p.db != nil && p.db.HasSeparateStateStore() { - trienodedb = p.db.GetStateStore() - } else { - trienodedb = p.db - } // Ensure the root is really present. The weak assumption // is the presence of root can indicate the presence of the // entire trie. - if !rawdb.HasLegacyTrieNode(trienodedb, root) { + if !rawdb.HasLegacyTrieNode(p.db, root) { // The special case is for clique based networks, it's possible // that two consecutive blocks will have same root. In this case // snapshot difflayer won't be created. So HEAD-127 may not paired @@ -296,7 +283,7 @@ func (p *Pruner) Prune(root common.Hash) error { // as the pruning target. var found bool for i := len(layers) - 2; i >= 2; i-- { - if rawdb.HasLegacyTrieNode(trienodedb, layers[i].Root()) { + if rawdb.HasLegacyTrieNode(p.db, layers[i].Root()) { root = layers[i].Root() found = true log.Info("Selecting middle-layer as the pruning target", "root", root, "depth", i) @@ -304,7 +291,7 @@ func (p *Pruner) Prune(root common.Hash) error { } } if !found { - if blob := rawdb.ReadLegacyTrieNode(trienodedb, p.snaptree.DiskRoot()); len(blob) != 0 { + if blob := rawdb.ReadLegacyTrieNode(p.db, p.snaptree.DiskRoot()); len(blob) != 0 { root = p.snaptree.DiskRoot() found = true log.Info("Selecting disk-layer as the pruning target", "root", root) diff --git a/core/state/statedb.go b/core/state/statedb.go index a68441e15f..24e32fc105 100644 --- a/core/state/statedb.go +++ b/core/state/statedb.go @@ -135,9 +135,6 @@ type StateDB struct { accessList *accessList accessEvents *AccessEvents - // block level access list - blockAccessList *types.BlockAccessListRecord - // Transient storage transientStorage transientStorage @@ -191,7 +188,6 @@ func NewWithReader(root common.Hash, db Database, reader Reader) (*StateDB, erro preimages: make(map[common.Hash][]byte), journal: newJournal(), accessList: newAccessList(), - blockAccessList: nil, transientStorage: newTransientStorage(), } if db.TrieDB().IsVerkle() { @@ -200,13 +196,6 @@ func NewWithReader(root common.Hash, db Database, reader Reader) (*StateDB, erro return sdb, nil } -func (s *StateDB) InitBlockAccessList() { - if s.blockAccessList != nil { - log.Warn("prepareBAL blockAccessList is not nil") - } - s.blockAccessList = &types.BlockAccessListRecord{Accounts: make(map[common.Address]types.AccountAccessListRecord)} -} - func (s *StateDB) SetNeedBadSharedStorage(needBadSharedStorage bool) { s.needBadSharedStorage = needBadSharedStorage } @@ -365,43 +354,6 @@ func (s *StateDB) GetNonce(addr common.Address) uint64 { return 0 } -func (s *StateDB) PreloadAccount(addr common.Address) { - if s.Empty(addr) { - return - } - s.GetCode(addr) -} - -func (s *StateDB) PreloadStorage(addr common.Address, key common.Hash) { - if s.Empty(addr) { - return - } - s.GetState(addr, key) -} -func (s *StateDB) PreloadAccountTrie(addr common.Address) { - if s.prefetcher == nil { - return - } - - addressesToPrefetch := []common.Address{addr} - if err := s.prefetcher.prefetch(common.Hash{}, s.originalRoot, common.Address{}, addressesToPrefetch, nil, false); err != nil { - log.Error("Failed to prefetch addresses", "addresses", len(addressesToPrefetch), "err", err) - } -} - -func (s *StateDB) PreloadStorageTrie(addr common.Address, key common.Hash) { - if s.prefetcher == nil { - return - } - obj := s.getStateObject(addr) - if obj == nil { - return - } - if err := s.prefetcher.prefetch(obj.addrHash, obj.origin.Root, obj.address, nil, []common.Hash{key}, true); err != nil { - log.Error("Failed to prefetch storage slot", "addr", obj.address, "key", key, "err", err) - } -} - // GetStorageRoot retrieves the storage root from the given address or empty // if object not found. func (s *StateDB) GetStorageRoot(addr common.Address) common.Hash { @@ -451,7 +403,6 @@ func (s *StateDB) GetCodeHash(addr common.Address) common.Hash { func (s *StateDB) GetState(addr common.Address, hash common.Hash) common.Hash { stateObject := s.getStateObject(addr) if stateObject != nil { - s.blockAccessList.AddStorage(addr, hash, uint32(s.txIndex), false) return stateObject.GetState(hash) } return common.Hash{} @@ -543,7 +494,6 @@ func (s *StateDB) SetCode(addr common.Address, code []byte, reason tracing.CodeC } func (s *StateDB) SetState(addr common.Address, key, value common.Hash) common.Hash { - s.blockAccessList.AddStorage(addr, key, uint32(s.txIndex), true) if stateObject := s.getOrNewStateObject(addr); stateObject != nil { return stateObject.SetState(key, value) } @@ -673,7 +623,6 @@ func (s *StateDB) deleteStateObject(addr common.Address) { // getStateObject retrieves a state object given by the address, returning nil if // the object is not found or was deleted in this execution context. func (s *StateDB) getStateObject(addr common.Address) *stateObject { - s.blockAccessList.AddAccount(addr, uint32(s.txIndex)) // Prefer live objects if any is available if obj := s.stateObjects[addr]; obj != nil { return obj @@ -773,14 +722,6 @@ func (s *StateDB) StateForPrefetch() *StateDB { return state } -func (s *StateDB) TransferBlockAccessList(prev *StateDB) { - if prev == nil { - return - } - s.blockAccessList = prev.blockAccessList - prev.blockAccessList = nil -} - // Copy creates a deep, independent copy of the state. // Snapshots of the copied state cannot be applied to the copy. func (s *StateDB) Copy() *StateDB { @@ -809,7 +750,6 @@ func (s *StateDB) Copy() *StateDB { // empty lists, so we do it anyway to not blow up if we ever decide copy them // in the middle of a transaction. accessList: s.accessList.Copy(), - blockAccessList: nil, transientStorage: s.transientStorage.Copy(), journal: s.journal.copy(), } @@ -1524,7 +1464,7 @@ func (s *StateDB) commitAndFlush(block uint64, deleteEmptyObjects bool, noStorag s.TrieDBCommits += time.Since(start) } } - s.reader, _ = s.db.Reader(s.originalRoot) + s.reader, err = s.db.Reader(s.originalRoot) return ret, err } @@ -1677,56 +1617,6 @@ func (s *StateDB) AccessEvents() *AccessEvents { return s.accessEvents } -func (s *StateDB) DumpAccessList(block *types.Block) { - if s.blockAccessList == nil { - return - } - accountCount := 0 - storageCount := 0 - dirtyStorageCount := 0 - for addr, account := range s.blockAccessList.Accounts { - accountCount++ - log.Debug(" DumpAccessList Address", "address", addr.Hex(), "txIndex", account.TxIndex) - for _, storageItem := range account.StorageItems { - log.Debug(" DumpAccessList Storage Item", "key", storageItem.Key.Hex(), "txIndex", storageItem.TxIndex, "dirty", storageItem.Dirty) - storageCount++ - if storageItem.Dirty { - dirtyStorageCount++ - } - } - } - log.Info("DumpAccessList", "blockNumber", block.NumberU64(), "GasUsed", block.GasUsed(), - "accountCount", accountCount, "storageCount", storageCount, "dirtyStorageCount", dirtyStorageCount) -} - -// GetEncodedBlockAccessList: convert BlockAccessListRecord to BlockAccessListEncode -func (s *StateDB) GetEncodedBlockAccessList(block *types.Block) *types.BlockAccessListEncode { - if s.blockAccessList == nil { - return nil - } - // encode block access list to rlp to propagate with the block - blockAccessList := types.BlockAccessListEncode{ - Version: 0, - Number: block.NumberU64(), - Hash: block.Hash(), - SignData: make([]byte, 65), - Accounts: make([]types.AccountAccessListEncode, 0), - } - for addr, account := range s.blockAccessList.Accounts { - accountAccessList := types.AccountAccessListEncode{ - TxIndex: account.TxIndex, - Address: addr, - StorageItems: make([]types.StorageAccessItem, 0), - } - for _, storageItem := range account.StorageItems { - accountAccessList.StorageItems = append(accountAccessList.StorageItems, storageItem) - } - blockAccessList.Accounts = append(blockAccessList.Accounts, accountAccessList) - } - - return &blockAccessList -} - func (s *StateDB) GetDirtyAccounts() []common.Address { accounts := make([]common.Address, 0, len(s.mutations)) for account := range s.mutations { diff --git a/core/state/sync_test.go b/core/state/sync_test.go index f48f936cdb..cae0e0a936 100644 --- a/core/state/sync_test.go +++ b/core/state/sync_test.go @@ -272,7 +272,7 @@ func testIterativeStateSync(t *testing.T, count int, commit bool, bypath bool, s } } batch := dstDb.NewBatch() - if err := sched.Commit(batch, nil); err != nil { + if err := sched.Commit(batch); err != nil { t.Fatalf("failed to commit data: %v", err) } batch.Write() @@ -377,7 +377,7 @@ func testIterativeDelayedStateSync(t *testing.T, scheme string) { nodeProcessed = len(nodeResults) } batch := dstDb.NewBatch() - if err := sched.Commit(batch, nil); err != nil { + if err := sched.Commit(batch); err != nil { t.Fatalf("failed to commit data: %v", err) } batch.Write() @@ -481,7 +481,7 @@ func testIterativeRandomStateSync(t *testing.T, count int, scheme string) { } } batch := dstDb.NewBatch() - if err := sched.Commit(batch, nil); err != nil { + if err := sched.Commit(batch); err != nil { t.Fatalf("failed to commit data: %v", err) } batch.Write() @@ -591,7 +591,7 @@ func testIterativeRandomDelayedStateSync(t *testing.T, scheme string) { } } batch := dstDb.NewBatch() - if err := sched.Commit(batch, nil); err != nil { + if err := sched.Commit(batch); err != nil { t.Fatalf("failed to commit data: %v", err) } batch.Write() @@ -708,7 +708,7 @@ func testIncompleteStateSync(t *testing.T, scheme string) { } } batch := dstDb.NewBatch() - if err := sched.Commit(batch, nil); err != nil { + if err := sched.Commit(batch); err != nil { t.Fatalf("failed to commit data: %v", err) } batch.Write() diff --git a/core/state_prefetcher.go b/core/state_prefetcher.go index a82f6646b2..5af32e891d 100644 --- a/core/state_prefetcher.go +++ b/core/state_prefetcher.go @@ -25,14 +25,11 @@ import ( "github.com/ethereum/go-ethereum/core/state" "github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/core/vm" - "github.com/ethereum/go-ethereum/log" "github.com/ethereum/go-ethereum/params" "golang.org/x/sync/errgroup" ) const prefetchMiningThread = 3 -const prefetchThreadBALSnapshot = 8 -const prefetchThreadBALTrie = 8 const checkInterval = 10 // statePrefetcher is a basic Prefetcher that executes transactions from a block @@ -132,147 +129,6 @@ func (p *statePrefetcher) Prefetch(transactions types.Transactions, header *type return } -func (p *statePrefetcher) PrefetchBALSnapshot(balPrefetch *types.BlockAccessListPrefetch, block *types.Block, txSize int, statedb *state.StateDB, interruptChan <-chan struct{}) { - accChan := make(chan struct { - txIndex uint32 - accAddr common.Address - }, prefetchThreadBALSnapshot) - - keyChan := make(chan struct { - txIndex uint32 - accAddr common.Address - key common.Hash - }, prefetchThreadBALSnapshot) - - // prefetch snapshot cache - for i := 0; i < prefetchThreadBALSnapshot; i++ { - go func() { - newStatedb := statedb.Copy() - for { - select { - case accAddr := <-accChan: - log.Debug("PrefetchBALSnapshot", "txIndex", accAddr.txIndex, "accAddr", accAddr.accAddr) - newStatedb.PreloadAccount(accAddr.accAddr) - case item := <-keyChan: - log.Debug("PrefetchBALSnapshot", "txIndex", item.txIndex, "accAddr", item.accAddr, "key", item.key) - newStatedb.PreloadStorage(item.accAddr, item.key) - case <-interruptChan: - return - } - } - }() - } - for txIndex := 0; txIndex < txSize; txIndex++ { - txAccessList := balPrefetch.AccessListItems[uint32(txIndex)] - for accAddr, storageItems := range txAccessList.Accounts { - select { - case accChan <- struct { - txIndex uint32 - accAddr common.Address - }{ - txIndex: uint32(txIndex), - accAddr: accAddr, - }: - case <-interruptChan: - return - } - for _, storageItem := range storageItems { - select { - case keyChan <- struct { - txIndex uint32 - accAddr common.Address - key common.Hash - }{ - txIndex: uint32(txIndex), - accAddr: accAddr, - key: storageItem.Key, - }: - case <-interruptChan: - return - } - } - } - } - log.Debug("PrefetchBALSnapshot dispatch finished") -} - -func (p *statePrefetcher) PrefetchBALTrie(balPrefetch *types.BlockAccessListPrefetch, block *types.Block, statedb *state.StateDB, interruptChan <-chan struct{}) { - accItemsChan := make(chan struct { - txIndex uint32 - accAddr common.Address - items []types.StorageAccessItemPrefetch - }, prefetchThreadBALTrie) - - for i := 0; i < prefetchThreadBALTrie; i++ { - go func() { - newStatedb := statedb.Copy() - for { - select { - case accItem := <-accItemsChan: - newStatedb.PreloadAccountTrie(accItem.accAddr) - log.Debug("PrefetchBALTrie", "txIndex", accItem.txIndex, "accAddr", accItem.accAddr) - for _, storageItem := range accItem.items { - if storageItem.Dirty { - log.Debug("PrefetchBALTrie", "txIndex", accItem.txIndex, "accAddr", accItem.accAddr, "storageItem", storageItem.Key, "dirty", storageItem.Dirty) - statedb.PreloadStorageTrie(accItem.accAddr, storageItem.Key) - } - } - case <-interruptChan: - return - } - } - }() - } - - for txIndex, txAccessList := range balPrefetch.AccessListItems { - for accAddr, storageItems := range txAccessList.Accounts { - select { - case accItemsChan <- struct { - txIndex uint32 - accAddr common.Address - items []types.StorageAccessItemPrefetch - }{ - txIndex: txIndex, - accAddr: accAddr, - items: storageItems, - }: - case <-interruptChan: - log.Warn("PrefetchBALTrie interrupted") - return - } - } - } - log.Debug("PrefetchBALTrie dispatch finished") -} - -func (p *statePrefetcher) PrefetchBAL(block *types.Block, statedb *state.StateDB, interruptChan <-chan struct{}) { - if block.BAL() == nil { - return - } - transactions := block.Transactions() - blockAccessList := block.BAL() - - // get index sorted block access list, each transaction has a list of accounts, each account has a list of storage items - // txIndex 0: - // account1: storage1_1, storage1_2, storage1_3 - // account2: storage2_1, storage2_2, storage2_3 - // txIndex 1: - // account3: storage3_1, storage3_2, storage3_3 - // ... - balPrefetch := types.BlockAccessListPrefetch{ - AccessListItems: make(map[uint32]types.TxAccessListPrefetch), - } - for _, account := range blockAccessList.Accounts { - balPrefetch.Update(&account) - } - - // prefetch snapshot cache - go p.PrefetchBALSnapshot(&balPrefetch, block, len(transactions), statedb, interruptChan) - - // prefetch MPT trie node cache - go p.PrefetchBALTrie(&balPrefetch, block, statedb, interruptChan) -} - // PrefetchMining processes the state changes according to the Ethereum rules by running // the transaction messages using the statedb, but any changes are discarded. The // only goal is to warm the state caches. Only used for mining stage. diff --git a/core/state_processor.go b/core/state_processor.go index 4299f37666..19c78b3942 100644 --- a/core/state_processor.go +++ b/core/state_processor.go @@ -185,7 +185,7 @@ func (p *StateProcessor) Process(block *types.Block, statedb *state.StateDB, cfg for _, receipt := range receipts { allLogs = append(allLogs, receipt.Logs...) } - statedb.DumpAccessList(block) + return &ProcessResult{ Receipts: receipts, Requests: requests, diff --git a/core/state_transition.go b/core/state_transition.go index 13c6433b75..2bfd1720b3 100644 --- a/core/state_transition.go +++ b/core/state_transition.go @@ -496,7 +496,7 @@ func (st *stateTransition) execute() (*ExecutionResult, error) { // Check whether the init code size has been exceeded. if rules.IsShanghai && contractCreation && len(msg.Data) > params.MaxInitCodeSize { - return nil, fmt.Errorf("%w: code size %v limit %v", ErrMaxInitCodeSizeExceeded, len(msg.Data), params.MaxInitCodeSize) + return nil, fmt.Errorf("%w: code size %v limit %v", vm.ErrMaxInitCodeSizeExceeded, len(msg.Data), params.MaxInitCodeSize) } // Execute the preparatory steps for state transition which includes: diff --git a/core/systemcontracts/pasteur/chapel/GovernorContract b/core/systemcontracts/pasteur/chapel/GovernorContract new file mode 100644 index 0000000000..861f33d447 --- /dev/null +++ b/core/systemcontracts/pasteur/chapel/GovernorContract @@ -0,0 +1 @@ +6080604052600436106103e85760003560e01c80637b3c71d311610208578063c28bc2fa11610118578063deaaa7cc116100ab578063ece40cc11161007a578063ece40cc114610e19578063f23a6e6114610e39578063f8ce560a14610e65578063fc0c546a14610e85578063fe0d94c114610ea657600080fd5b8063deaaa7cc14610cda578063e23a9a5214610d0e578063ea0217cf14610dd9578063eb9019d414610df957600080fd5b8063da95691a116100e7578063da95691a14610c2f578063dd42a1dd14610c4f578063dd4e2ba514610c74578063ddf0b00914610cba57600080fd5b8063c28bc2fa14610bbd578063c59057e414610bd0578063d07f91e914610bf0578063d33219b414610c1057600080fd5b8063a7713a701161019b578063b187bd261161016a578063b187bd2614610b23578063b58131b014610b41578063bc197c8114610b56578063c01f9e3714610b82578063c170ec0b14610ba257600080fd5b8063a7713a7014610aae578063a890c91014610ac3578063ab58fb8e14610ae3578063ac43175114610b0357600080fd5b806384b0196e116101d757806384b0196e14610a2657806391ddadf414610a4e57806397c3d33414610a7a5780639a802a6d14610a8e57600080fd5b80637b3c71d3146109bc5780637d5e81e2146109dc5780638129fc1c146109fc5780638456cb5914610a1157600080fd5b806332b8113e116103035780634838d1651161029657806354fd4d501161026557806354fd4d5014610912578063567813881461093c5780635f398a141461095c57806360c4247f1461097c57806370b0f6601461099c57600080fd5b80634838d1651461087c5780634a49ac4c146108ac5780634bf5d7e9146108cc578063533ddd14146108e157600080fd5b806340e58ee5116102d257806340e58ee5146107d1578063417c73a7146107f15780634385963214610811578063452115d61461085c57600080fd5b806332b8113e146107455780633932abb11461076e5780633bccf4fd146107845780633e4f49e6146107a457600080fd5b8063150b7a021161037b5780632656227d1161034a5780632656227d146106975780632d63f693146106aa5780632fe3e261146106e1578063328dd9821461071557600080fd5b8063150b7a02146105f0578063160cbed71461063457806317977c611461065457806324bc1a641461068257600080fd5b8063046f7da2116103b7578063046f7da21461054357806306f3f9e61461055857806306fdde0314610578578063143489d01461059a57600080fd5b8063013cf08b1461045857806301ffc9a7146104d357806302a251a314610503578063034201811461052357600080fd5b3661045357306103f6610eb9565b6001600160a01b0316146104515760405162461bcd60e51b815260206004820152601f60248201527f476f7665726e6f723a206d7573742073656e6420746f206578656375746f720060448201526064015b60405180910390fd5b005b600080fd5b34801561046457600080fd5b50610478610473366004615ca2565b610ed3565b604080519a8b526001600160a01b0390991660208b0152978901969096526060880194909452608087019290925260a086015260c085015260e084015215156101008301521515610120820152610140015b60405180910390f35b3480156104df57600080fd5b506104f36104ee366004615cbb565b610f8e565b60405190151581526020016104ca565b34801561050f57600080fd5b50610195545b6040519081526020016104ca565b34801561052f57600080fd5b5061051561053e366004615e01565b610f9f565b34801561054f57600080fd5b50610451611097565b34801561056457600080fd5b50610451610573366004615ca2565b611127565b34801561058457600080fd5b5061058d6111b2565b6040516104ca9190615ef7565b3480156105a657600080fd5b506105d86105b5366004615ca2565b60009081526101636020526040902054600160401b90046001600160a01b031690565b6040516001600160a01b0390911681526020016104ca565b3480156105fc57600080fd5b5061061b61060b366004615f1f565b630a85bd0160e11b949350505050565b6040516001600160e01b031990911681526020016104ca565b34801561064057600080fd5b5061051561064f3660046160f6565b611245565b34801561066057600080fd5b5061051561066f366004616185565b6102c36020526000908152604090205481565b34801561068e57600080fd5b50610515611330565b6105156106a53660046160f6565b611356565b3480156106b657600080fd5b506105156106c5366004615ca2565b600090815261016360205260409020546001600160401b031690565b3480156106ed57600080fd5b506105157fb3b3f3b703cd84ce352197dcff232b1b5d3cfb2025ce47cf04742d0651f1af8881565b34801561072157600080fd5b50610735610730366004615ca2565b611449565b6040516104ca949392919061626b565b34801561075157600080fd5b5061028f546040516001600160401b0390911681526020016104ca565b34801561077a57600080fd5b5061019454610515565b34801561079057600080fd5b5061051561079f3660046162b8565b6116db565b3480156107b057600080fd5b506107c46107bf366004615ca2565b611751565b6040516104ca919061631c565b3480156107dd57600080fd5b506104516107ec366004615ca2565b61175c565b3480156107fd57600080fd5b5061045161080c366004616185565b611787565b34801561081d57600080fd5b506104f361082c366004616344565b60008281526101c6602090815260408083206001600160a01b038516845260080190915290205460ff1692915050565b34801561086857600080fd5b506105156108773660046160f6565b611808565b34801561088857600080fd5b506104f3610897366004616185565b60016020526000908152604090205460ff1681565b3480156108b857600080fd5b506104516108c7366004616185565b611816565b3480156108d857600080fd5b5061058d611891565b3480156108ed57600080fd5b506104f36108fc366004616185565b6102c16020526000908152604090205460ff1681565b34801561091e57600080fd5b506040805180820190915260018152603160f81b602082015261058d565b34801561094857600080fd5b50610515610957366004616374565b61193e565b34801561096857600080fd5b506105156109773660046163a0565b611967565b34801561098857600080fd5b50610515610997366004615ca2565b6119b1565b3480156109a857600080fd5b506104516109b7366004615ca2565b611a66565b3480156109c857600080fd5b506105156109d7366004616423565b611aee565b3480156109e857600080fd5b506105156109f736600461647c565b611b40565b348015610a0857600080fd5b50610451611c5b565b348015610a1d57600080fd5b50610451611e8c565b348015610a3257600080fd5b50610a3b611f22565b6040516104ca979695949392919061651c565b348015610a5a57600080fd5b50610a63611fc0565b60405165ffffffffffff90911681526020016104ca565b348015610a8657600080fd5b506064610515565b348015610a9a57600080fd5b50610515610aa936600461657e565b612034565b348015610aba57600080fd5b5061051561204b565b348015610acf57600080fd5b50610451610ade366004616185565b612078565b348015610aef57600080fd5b50610515610afe366004615ca2565b612100565b348015610b0f57600080fd5b50610451610b1e3660046165d6565b61219c565b348015610b2f57600080fd5b5060005462010000900460ff166104f3565b348015610b4d57600080fd5b506105156128e1565b348015610b6257600080fd5b5061061b610b71366004616635565b63bc197c8160e01b95945050505050565b348015610b8e57600080fd5b50610515610b9d366004615ca2565b6128ed565b348015610bae57600080fd5b506102c2546104f39060ff1681565b610451610bcb3660046166c8565b6128f8565b348015610bdc57600080fd5b50610515610beb3660046160f6565b612a08565b348015610bfc57600080fd5b50610451610c0b36600461670b565b612a42565b348015610c1c57600080fd5b5061022b546001600160a01b03166105d8565b348015610c3b57600080fd5b50610515610c4a366004616734565b612aca565b348015610c5b57600080fd5b50600054630100000090046001600160a01b03166105d8565b348015610c8057600080fd5b5060408051808201909152601a81527f737570706f72743d627261766f2671756f72756d3d627261766f000000000000602082015261058d565b348015610cc657600080fd5b50610451610cd5366004615ca2565b612b51565b348015610ce657600080fd5b506105157f150214d74d59b7d1e90c73fc22ef3d991dd0a76b046543d4d80ab92d2a50328f81565b348015610d1a57600080fd5b50610da9610d29366004616344565b60408051606081018252600080825260208201819052918101919091525060009182526101c6602090815260408084206001600160a01b0393909316845260089092018152918190208151606081018352905460ff8082161515835261010082041693820193909352620100009092046001600160601b03169082015290565b6040805182511515815260208084015160ff1690820152918101516001600160601b0316908201526060016104ca565b348015610de557600080fd5b50610451610df4366004615ca2565b612b74565b348015610e0557600080fd5b50610515610e143660046167d5565b612bfc565b348015610e2557600080fd5b50610451610e34366004615ca2565b612c1d565b348015610e4557600080fd5b5061061b610e54366004616801565b63f23a6e6160e01b95945050505050565b348015610e7157600080fd5b50610515610e80366004615ca2565b612ca5565b348015610e9157600080fd5b506101f8546105d8906001600160a01b031681565b610451610eb4366004615ca2565b612d34565b6000610ece61022b546001600160a01b031690565b905090565b8060008080808080808080610ee78a612100565b60008c815261016360205260409020549098506001600160401b03169650610f0e8b6128ed565b60008c81526101c66020526040812080546005820154600683015460078401546001600160a01b039093169e50949a509850929650919450610f4f8d611751565b90506002816007811115610f6557610f65616306565b1493506007816007811115610f7c57610f7c616306565b14925050509193959799509193959799565b6000610f9982612d57565b92915050565b60008061104361103b7fb3b3f3b703cd84ce352197dcff232b1b5d3cfb2025ce47cf04742d0651f1af888c8c8c8c604051610fdb929190616869565b60405180910390208b80519060200120604051602001611020959493929190948552602085019390935260ff9190911660408401526060830152608082015260a00190565b60405160208183030381529060405280519060200120612d7c565b868686612da9565b90506110898a828b8b8b8080601f0160208091040260200160405190810160405280939291908181526020018383808284376000920191909152508d9250612dc7915050565b9a9950505050505050505050565b600054630100000090046001600160a01b031633146110c9576040516306fbb1e360e01b815260040160405180910390fd5b60005462010000900460ff166110f257604051636cd6020160e01b815260040160405180910390fd5b6000805462ff0000191681556040517f62451d457bc659158be6e6247f56ec1df424a5c7597f71c20c2bc44e0965c8f99190a1565b61112f610eb9565b6001600160a01b0316336001600160a01b03161461115f5760405162461bcd60e51b815260040161044890616879565b30611168610eb9565b6001600160a01b0316146111a65760008036604051611188929190616869565b604051809103902090505b8061119f610164612e6a565b0361119357505b6111af81612ee9565b50565b606061016280546111c2906168b0565b80601f01602080910402602001604051908101604052809291908181526020018280546111ee906168b0565b801561123b5780601f106112105761010080835404028352916020019161123b565b820191906000526020600020905b81548152906001019060200180831161121e57829003601f168201915b5050505050905090565b6000805462010000900460ff161561127057604051631785c68160e01b815260040160405180910390fd5b3360009081526001602052604090205460ff16156112a15760405163b1d02c3d60e01b815260040160405180910390fd5b60005b855181101561131a576102c160008783815181106112c4576112c46168ea565b6020908102919091018101516001600160a01b031682528101919091526040016000205460ff1661130857604051630b094f2760e31b815260040160405180910390fd5b8061131281616916565b9150506112a4565b506113278585858561305a565b95945050505050565b6000610ece600161133f611fc0565b611349919061692f565b65ffffffffffff16612ca5565b60008061136586868686612a08565b9050600061137282611751565b9050600481600781111561138857611388616306565b14806113a5575060058160078111156113a3576113a3616306565b145b6113c15760405162461bcd60e51b815260040161044890616955565b6000828152610163602052604090819020600201805460ff19166001179055517f712ae1383f79ac853f8d882153778e0260ef8f03b504e2866e0593e04d2b291f906114109084815260200190565b60405180910390a1611425828888888861325f565b6114328288888888613300565b61143f82888888886133e2565b5095945050505050565b60608060608060006101c66000878152602001908152602001600020905080600101816002018260030183600401838054806020026020016040519081016040528092919081815260200182805480156114cc57602002820191906000526020600020905b81546001600160a01b031681526001909101906020018083116114ae575b505050505093508280548060200260200160405190810160405280929190818152602001828054801561151e57602002820191906000526020600020905b81548152602001906001019080831161150a575b5050505050925081805480602002602001604051908101604052809291908181526020016000905b828210156115f2578382906000526020600020018054611565906168b0565b80601f0160208091040260200160405190810160405280929190818152602001828054611591906168b0565b80156115de5780601f106115b3576101008083540402835291602001916115de565b820191906000526020600020905b8154815290600101906020018083116115c157829003601f168201915b505050505081526020019060010190611546565b50505050915080805480602002602001604051908101604052809291908181526020016000905b828210156116c5578382906000526020600020018054611638906168b0565b80601f0160208091040260200160405190810160405280929190818152602001828054611664906168b0565b80156116b15780601f10611686576101008083540402835291602001916116b1565b820191906000526020600020905b81548152906001019060200180831161169457829003601f168201915b505050505081526020019060010190611619565b5050505090509450945094509450509193509193565b604080517f150214d74d59b7d1e90c73fc22ef3d991dd0a76b046543d4d80ab92d2a50328f602082015290810186905260ff8516606082015260009081906117299061103b90608001611020565b90506117468782886040518060200160405280600081525061341d565b979650505050505050565b6000610f9982613440565b60008060008061176b8561358d565b935093509350935061177f84848484611808565b505050505050565b600054630100000090046001600160a01b031633146117b9576040516306fbb1e360e01b815260040160405180910390fd5b6001600160a01b0381166000818152600160208190526040808320805460ff1916909217909155517f7fd26be6fc92aff63f1f4409b2b2ddeb272a888031d7f55ec830485ec61941869190a250565b60006113278585858561381e565b600054630100000090046001600160a01b03163314611848576040516306fbb1e360e01b815260040160405180910390fd5b6001600160a01b038116600081815260016020526040808220805460ff19169055517fe0db3499b7fdc3da4cddff5f45d694549c19835e7f719fb5606d3ad1a5de40119190a250565b6101f85460408051634bf5d7e960e01b815290516060926001600160a01b031691634bf5d7e99160048083019260009291908290030181865afa9250505080156118fd57506040513d6000823e601f3d908101601f191682016040526118fa9190810190616996565b60015b611939575060408051808201909152601d81527f6d6f64653d626c6f636b6e756d6265722666726f6d3d64656661756c74000000602082015290565b919050565b60008033905061195f8482856040518060200160405280600081525061341d565b949350505050565b60008033905061174687828888888080601f0160208091040260200160405190810160405280939291908181526020018383808284376000920191909152508a9250612dc7915050565b61025e546000908082036119ca57505061025d54919050565b600061025e6119da600184616a03565b815481106119ea576119ea6168ea565b60009182526020918290206040805180820190915291015463ffffffff8116808352600160201b9091046001600160e01b03169282019290925291508410611a4057602001516001600160e01b03169392505050565b611a55611a4c856138e9565b61025e90613952565b6001600160e01b0316949350505050565b611a6e610eb9565b6001600160a01b0316336001600160a01b031614611a9e5760405162461bcd60e51b815260040161044890616879565b30611aa7610eb9565b6001600160a01b031614611ae55760008036604051611ac7929190616869565b604051809103902090505b80611ade610164612e6a565b03611ad257505b6111af81613a05565b600080339050611b3686828787878080601f01602080910402602001604051908101604052809392919081815260200183838082843760009201919091525061341d92505050565b9695505050505050565b6000805462010000900460ff1615611b6b57604051631785c68160e01b815260040160405180910390fd5b3360009081526001602052604090205460ff1615611b9c5760405163b1d02c3d60e01b815260040160405180910390fd5b611ba4613a48565b3360009081526102c360205260409020548015611c19576000611bc682611751565b90506001816007811115611bdc57611bdc616306565b1480611bf957506000816007811115611bf757611bf7616306565b145b15611c175760405163867f3ee560e01b815260040160405180910390fd5b505b825160208401206000611c2e88888885612a08565b3360009081526102c3602052604090208190559050611c4f88888888613af3565b98975050505050505050565b600054610100900460ff1615808015611c7b5750600054600160ff909116105b80611c955750303b158015611c95575060005460ff166001145b611cf85760405162461bcd60e51b815260206004820152602e60248201527f496e697469616c697a61626c653a20636f6e747261637420697320616c72656160448201526d191e481a5b9a5d1a585b1a5e995960921b6064820152608401610448565b6000805460ff191660011790558015611d1b576000805461ff0019166101001790555b334114611d3b5760405163022d8c9560e31b815260040160405180910390fd5b3a15611d5a576040516383f1b1d360e01b815260040160405180910390fd5b611d866040518060400160405280600b81526020016a2129a1a3b7bb32b93737b960a91b815250613b5b565b611db2611d9560036000616a2c565b611da3600362015180616a2c565b68056bc75e2d63100000613bb2565b611dba613be9565b611dc5612005613c10565b611dd0612006613c40565b611dda600a613c70565b611def611dea6003610e10616a2c565b613ca0565b6110076000526102c16020527f2f832952f0ef896b8c8edd6d16a2e4f2591a90375e33021e3b9ff197f3793fc0805460ff19166001179055611e447330151da466ec8ab345bef3d6983023e050fb0673613cd0565b80156111af576000805461ff0019169055604051600181527f7f26b83ff96e1f2b6a682f133852f6798a09c465da95921460cefb38474024989060200160405180910390a150565b600054630100000090046001600160a01b03163314611ebe576040516306fbb1e360e01b815260040160405180910390fd5b60005462010000900460ff1615611ee857604051631785c68160e01b815260040160405180910390fd5b6000805462ff00001916620100001781556040517f9e87fac88ff661f02d44f95383c817fece4bce600a3dab7a54406878b965e7529190a1565b6000606080600080600060606098546000801b148015611f425750609954155b611f865760405162461bcd60e51b81526020600482015260156024820152741152540dcc4c8e88155b9a5b9a5d1a585b1a5e9959605a1b6044820152606401610448565b611f8e613d23565b611f96613d32565b60408051600080825260208201909252600f60f81b9b939a50919850469750309650945092509050565b6101f854604080516324776b7d60e21b815290516000926001600160a01b0316916391ddadf49160048083019260209291908290030181865afa925050508015612027575060408051601f3d908101601f1916820190925261202491810190616a4e565b60015b61193957610ece43613d41565b6000612041848484613da8565b90505b9392505050565b61025e54600090156120705761206261025e613e1f565b6001600160e01b0316905090565b5061025d5490565b612080610eb9565b6001600160a01b0316336001600160a01b0316146120b05760405162461bcd60e51b815260040161044890616879565b306120b9610eb9565b6001600160a01b0316146120f757600080366040516120d9929190616869565b604051809103902090505b806120f0610164612e6a565b036120e457505b6111af81613e4f565b61022b54600082815261022c602052604080822054905163d45c443560e01b81526004810191909152909182916001600160a01b039091169063d45c443590602401602060405180830381865afa15801561215f573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906121839190616a76565b9050806001146121935780612044565b60009392505050565b33611007146121c257604051630f22c43960e41b81526110076004820152602401610448565b6122286040518060400160405280600b81526020016a766f74696e6744656c617960a81b81525085858080601f0160208091040260200160405190810160405280939291908181526020018383808284376000920191909152509293925050613eba9050565b156122dd57602081146122565783838383604051630a5a604160e01b81526004016104489493929190616ab8565b604080516020601f8401819004810282018101909252828152600091612297918585808385018382808284376000920191909152509293925050613f139050565b90508015806122a857506201518081115b156122ce5784848484604051630a5a604160e01b81526004016104489493929190616ab8565b6122d781613a05565b5061289e565b6123446040518060400160405280600c81526020016b1d9bdd1a5b99d4195c9a5bd960a21b81525085858080601f0160208091040260200160405190810160405280939291908181526020018383808284376000920191909152509293925050613eba9050565b156123f357602081146123725783838383604051630a5a604160e01b81526004016104489493929190616ab8565b604080516020601f84018190048102820181019092528281526000916123b3918585808385018382808284376000920191909152509293925050613f139050565b90508015806123c4575062278d0081115b156123ea5784848484604051630a5a604160e01b81526004016104489493929190616ab8565b6122d781613f18565b61245f604051806040016040528060118152602001701c1c9bdc1bdcd85b151a1c995cda1bdb19607a1b81525085858080601f0160208091040260200160405190810160405280939291908181526020018383808284376000920191909152509293925050613eba9050565b15612515576020811461248d5783838383604051630a5a604160e01b81526004016104489493929190616ab8565b604080516020601f84018190048102820181019092528281526000916124ce918585808385018382808284376000920191909152509293925050613f139050565b90508015806124e6575069021e19e0c9bab240000081115b1561250c5784848484604051630a5a604160e01b81526004016104489493929190616ab8565b6122d781613fbb565b61257f6040518060400160405280600f81526020016e38bab7b93ab6a73ab6b2b930ba37b960891b81525085858080601f0160208091040260200160405190810160405280939291908181526020018383808284376000920191909152509293925050613eba9050565b1561262e57602081146125ad5783838383604051630a5a604160e01b81526004016104489493929190616ab8565b604080516020601f84018190048102820181019092528281526000916125ee918585808385018382808284376000920191909152509293925050613f139050565b905060058110806125ff5750601481115b156126255784848484604051630a5a604160e01b81526004016104489493929190616ab8565b6122d781612ee9565b61269d604051806040016040528060148152602001736d696e506572696f64416674657251756f72756d60601b81525085858080601f0160208091040260200160405190810160405280939291908181526020018383808284376000920191909152509293925050613eba9050565b1561276357600881146126cb5783838383604051630a5a604160e01b81526004016104489493929190616ab8565b6000612711600884848080601f0160208091040260200160405190810160405280939291908181526020018383808284376000920191909152509293925050613f139050565b90506001600160401b038116158061273457506202a300816001600160401b0316115b1561275a5784848484604051630a5a604160e01b81526004016104489493929190616ab8565b6122d781613ffe565b6127cf6040518060400160405280601181526020017033b7bb32b93737b9283937ba32b1ba37b960791b81525085858080601f0160208091040260200160405190810160405280939291908181526020018383808284376000920191909152509293925050613eba9050565b1561287d57601481146127fd5783838383604051630a5a604160e01b81526004016104489493929190616ab8565b6000612843601484848080601f0160208091040260200160405190810160405280939291908181526020018383808284376000920191909152509293925050613f139050565b90506001600160a01b0381166128745784848484604051630a5a604160e01b81526004016104489493929190616ab8565b6122d78161406a565b838383836040516325ee20d560e21b81526004016104489493929190616ab8565b7ff1ce9b2cbf50eeb05769a29e2543fd350cab46894a7dd9978a12d534bb20e633848484846040516128d39493929190616ab8565b60405180910390a150505050565b6000610ece6101965490565b6000610f99826140d6565b612900610eb9565b6001600160a01b0316336001600160a01b0316146129305760405162461bcd60e51b815260040161044890616879565b30612939610eb9565b6001600160a01b0316146129775760008036604051612959929190616869565b604051809103902090505b80612970610164612e6a565b0361296457505b600080856001600160a01b0316858585604051612995929190616869565b60006040518083038185875af1925050503d80600081146129d2576040519150601f19603f3d011682016040523d82523d6000602084013e6129d7565b606091505b50915091506129ff8282604051806060016040528060288152602001616f1560289139614114565b50505050505050565b600084848484604051602001612a219493929190616adf565b60408051601f19818403018152919052805160209091012095945050505050565b612a4a610eb9565b6001600160a01b0316336001600160a01b031614612a7a5760405162461bcd60e51b815260040161044890616879565b30612a83610eb9565b6001600160a01b031614612ac15760008036604051612aa3929190616869565b604051809103902090505b80612aba610164612e6a565b03612aae57505b6111af81613ffe565b60008251845114612b2e5760405162461bcd60e51b815260206004820152602860248201527f476f7665726e6f72427261766f3a20696e76616c6964207369676e61747572656044820152670e640d8cadccee8d60c31b6064820152608401610448565b612b3c33878787878761412d565b611b368686612b4b87876141eb565b85611b40565b600080600080612b608561358d565b935093509350935061177f84848484611245565b612b7c610eb9565b6001600160a01b0316336001600160a01b031614612bac5760405162461bcd60e51b815260040161044890616879565b30612bb5610eb9565b6001600160a01b031614612bf35760008036604051612bd5929190616869565b604051809103902090505b80612bec610164612e6a565b03612be057505b6111af81613f18565b60006120448383612c1860408051602081019091526000815290565b613da8565b612c25610eb9565b6001600160a01b0316336001600160a01b031614612c555760405162461bcd60e51b815260040161044890616879565b30612c5e610eb9565b6001600160a01b031614612c9c5760008036604051612c7e929190616869565b604051809103902090505b80612c95610164612e6a565b03612c8957505b6111af81613fbb565b60006064612cb2836119b1565b6101f854604051632394e7a360e21b8152600481018690526001600160a01b0390911690638e539e8c90602401602060405180830381865afa158015612cfc573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612d209190616a76565b612d2a9190616b2a565b610f999190616a2c565b600080600080612d438561358d565b935093509350935061177f84848484611356565b60006001600160e01b03198216636e665ced60e01b1480610f995750610f998261431d565b6000610f99612d896143b9565b8360405161190160f01b8152600281019290925260228201526042902090565b6000806000612dba878787876143c3565b9150915061143f81614487565b6000805462010000900460ff1615612df257604051631785c68160e01b815260040160405180910390fd5b3360009081526001602052604090205460ff1615612e235760405163b1d02c3d60e01b815260040160405180910390fd5b6001600160a01b03851660009081526001602052604090205460ff1615612e5d5760405163b1d02c3d60e01b815260040160405180910390fd5b611b3686868686866145d1565b6000612e858254600f81810b600160801b909204900b131590565b15612ea357604051631ed9509560e11b815260040160405180910390fd5b508054600f0b6000818152600180840160205260408220805492905583546fffffffffffffffffffffffffffffffff191692016001600160801b03169190911790915590565b6064811115612f6c5760405162461bcd60e51b815260206004820152604360248201527f476f7665726e6f72566f74657351756f72756d4672616374696f6e3a2071756f60448201527f72756d4e756d657261746f72206f7665722071756f72756d44656e6f6d696e616064820152623a37b960e91b608482015260a401610448565b6000612f7661204b565b90508015801590612f88575061025e54155b15612fed57604080518082019091526000815261025e9060208101612fac846146d4565b6001600160e01b039081169091528254600181018455600093845260209384902083519490930151909116600160201b0263ffffffff909316929092179101555b61301b613008612ffb611fc0565b65ffffffffffff166138e9565b613011846146d4565b61025e919061473d565b505060408051828152602081018490527f0553476bf02ef2726e8ce5ced78d63e26e602e4a2257b1f559418e24b4633997910160405180910390a15050565b60008061306986868686612a08565b9050600461307682611751565b600781111561308757613087616306565b146130a45760405162461bcd60e51b815260040161044890616955565b61022b546040805163793d064960e11b815290516000926001600160a01b03169163f27a0c929160048083019260209291908290030181865afa1580156130ef573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906131139190616a76565b61022b5460405163b1c5f42760e01b81529192506001600160a01b03169063b1c5f4279061314e908a908a908a906000908b90600401616b41565b602060405180830381865afa15801561316b573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061318f9190616a76565b600083815261022c60205260408082209290925561022b5491516308f2a0bb60e41b81526001600160a01b0390921691638f2a0bb0916131dc918b918b918b91908b908990600401616b8f565b600060405180830381600087803b1580156131f657600080fd5b505af115801561320a573d6000803e3d6000fd5b505050507f9a2e42fd6722813d69113e7d0079d3d940171428df7373df9c7f7617cfda289282824261323c9190616be7565b604080519283526020830191909152015b60405180910390a15095945050505050565b30613268610eb9565b6001600160a01b0316146132f95760005b845181101561177f57306001600160a01b031685828151811061329e5761329e6168ea565b60200260200101516001600160a01b0316036132e9576132e98382815181106132c9576132c96168ea565b60200260200101518051906020012061016461475890919063ffffffff16565b6132f281616916565b9050613279565b5050505050565b60005462010000900460ff161561332a57604051631785c68160e01b815260040160405180910390fd5b3360009081526001602052604090205460ff161561335b5760405163b1d02c3d60e01b815260040160405180910390fd5b60005b84518110156133d4576102c1600086838151811061337e5761337e6168ea565b6020908102919091018101516001600160a01b031682528101919091526040016000205460ff166133c257604051630b094f2760e31b815260040160405180910390fd5b806133cc81616916565b91505061335e565b506132f98585858585614794565b306133eb610eb9565b6001600160a01b0316146132f95761016454600f81810b600160801b909204900b13156132f9576000610164556132f9565b60006113278585858561343b60408051602081019091526000815290565b612dc7565b60008061344c83614809565b9050600481600781111561346257613462616306565b1461346d5792915050565b600083815261022c602052604090205480613489575092915050565b61022b54604051632ab0f52960e01b8152600481018390526001600160a01b0390911690632ab0f52990602401602060405180830381865afa1580156134d3573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906134f79190616bfa565b15613506575060079392505050565b61022b54604051632c258a9f60e11b8152600481018390526001600160a01b039091169063584b153e90602401602060405180830381865afa158015613550573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906135749190616bfa565b15613583575060059392505050565b5060029392505050565b60608060606000806101c660008781526020019081526020016000209050806001018160020161375f83600301805480602002602001604051908101604052809291908181526020016000905b828210156136865783829060005260206000200180546135f9906168b0565b80601f0160208091040260200160405190810160405280929190818152602001828054613625906168b0565b80156136725780601f1061364757610100808354040283529160200191613672565b820191906000526020600020905b81548152906001019060200180831161365557829003601f168201915b5050505050815260200190600101906135da565b50505060048601805460408051602080840282018101909252828152935060009084015b828210156137565783829060005260206000200180546136c9906168b0565b80601f01602080910402602001604051908101604052809291908181526020018280546136f5906168b0565b80156137425780601f1061371757610100808354040283529160200191613742565b820191906000526020600020905b81548152906001019060200180831161372557829003601f168201915b5050505050815260200190600101906136aa565b505050506141eb565b60098401548354604080516020808402820181019092528281529186918301828280156137b557602002820191906000526020600020905b81546001600160a01b03168152600190910190602001808311613797575b505050505093508280548060200260200160405190810160405280929190818152602001828054801561380757602002820191906000526020600020905b8154815260200190600101908083116137f3575b505050505092509450945094509450509193509193565b60008061382d86868686612a08565b60008181526101c660205260409020549091506001600160a01b031633811480613881575061385a6128e1565b61387f826001613868611fc0565b613872919061692f565b65ffffffffffff16612bfc565b105b6138dd5760405162461bcd60e51b815260206004820152602760248201527f476f7665726e6f72427261766f3a2070726f706f7365722061626f76652074686044820152661c995cda1bdb1960ca1b6064820152608401610448565b61174687878787614941565b600063ffffffff82111561394e5760405162461bcd60e51b815260206004820152602660248201527f53616665436173743a2076616c756520646f65736e27742066697420696e203360448201526532206269747360d01b6064820152608401610448565b5090565b8154600090818160058111156139af57600061396d8461494f565b6139779085616a03565b60008881526020902090915081015463ffffffff908116908716101561399f578091506139ad565b6139aa816001616be7565b92505b505b60006139bd87878585614a37565b905080156139f8576139e2876139d4600184616a03565b600091825260209091200190565b54600160201b90046001600160e01b0316611746565b6000979650505050505050565b6101945460408051918252602082018390527fc565b045403dc03c2eea82b81a0465edad9e2e7fc4d97e11421c209da93d7a93910160405180910390a161019455565b6102c25460ff16613af1576a084595161401484a0000006120056001600160a01b03166318160ddd6040518163ffffffff1660e01b8152600401602060405180830381865afa158015613a9f573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613ac39190616a76565b1015613ae2576040516311b6707f60e01b815260040160405180910390fd5b6102c2805460ff191660011790555b565b6000613b4f33868686516001600160401b03811115613b1457613b14615d3e565b604051908082528060200260200182016040528015613b4757816020015b6060815260200190600190039081613b325790505b50878761412d565b61132785858585614a8d565b600054610100900460ff16613b825760405162461bcd60e51b815260040161044890616c1c565b613ba981613ba46040805180820190915260018152603160f81b602082015290565b614e6c565b6111af81614ebb565b600054610100900460ff16613bd95760405162461bcd60e51b815260040161044890616c1c565b613be4838383614ef3565b505050565b600054610100900460ff16613af15760405162461bcd60e51b815260040161044890616c1c565b600054610100900460ff16613c375760405162461bcd60e51b815260040161044890616c1c565b6111af81614f35565b600054610100900460ff16613c675760405162461bcd60e51b815260040161044890616c1c565b6111af81614f7f565b600054610100900460ff16613c975760405162461bcd60e51b815260040161044890616c1c565b6111af81614fa6565b600054610100900460ff16613cc75760405162461bcd60e51b815260040161044890616c1c565b6111af81614fcd565b600054610100900460ff16613cf75760405162461bcd60e51b815260040161044890616c1c565b600080546001600160a01b039092166301000000026301000000600160b81b0319909216919091179055565b6060609a80546111c2906168b0565b6060609b80546111c2906168b0565b600065ffffffffffff82111561394e5760405162461bcd60e51b815260206004820152602660248201527f53616665436173743a2076616c756520646f65736e27742066697420696e203460448201526538206269747360d01b6064820152608401610448565b6101f854604051630748d63560e31b81526001600160a01b038581166004830152602482018590526000921690633a46b1a890604401602060405180830381865afa158015613dfb573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906120419190616a76565b8054600090801561219357613e39836139d4600184616a03565b54600160201b90046001600160e01b0316612044565b61022b54604080516001600160a01b03928316815291831660208301527f08f74ea46ef7894f65eabfb5e6e695de773a000b47c529ab559178069b226401910160405180910390a161022b80546001600160a01b0319166001600160a01b0392909216919091179055565b600081604051602001613ecd9190616c67565b6040516020818303038152906040528051906020012083604051602001613ef49190616c67565b6040516020818303038152906040528051906020012014905092915050565b015190565b60008111613f785760405162461bcd60e51b815260206004820152602760248201527f476f7665726e6f7253657474696e67733a20766f74696e6720706572696f6420604482015266746f6f206c6f7760c81b6064820152608401610448565b6101955460408051918252602082018390527f7e3f7f0708a84de9203036abaa450dccc85ad5ff52f78c170f3edb55cf5e8828910160405180910390a161019555565b6101965460408051918252602082018390527fccb45da8d5717e6c4544694297c4ba5cf151d455c9bb0ed4fc7a38411bc05461910160405180910390a161019655565b61028f54604080516001600160401b03928316815291831660208301527f7ca4ac117ed3cdce75c1161d8207c440389b1a15d69d096831664657c07dafc2910160405180910390a161028f805467ffffffffffffffff19166001600160401b0392909216919091179055565b600080546040516001600160a01b0380851693630100000090930416917f44fc1b38a4abaa91ebd1b628a5b259a698f86238c8217d68f516e87769c60c0b91a3600080546001600160a01b039092166301000000026301000000600160b81b0319909216919091179055565b60008181526101636020526040812060010154610f99906001600160401b0316600084815261029060205260409020546001600160401b0316614ff4565b60608315614123575081612044565b612044838361500a565b80516020820120600061414b878761414588886141eb565b85612a08565b60008181526101c6602052604090206009810154919250906141e05780546001600160a01b0319166001600160a01b038a16178155875161419590600183019060208b0190615ad9565b5086516141ab90600283019060208a0190615b3a565b5085516141c19060038301906020890190615b75565b5084516141d79060048301906020880190615bc7565b50600981018390555b505050505050505050565b6060600082516001600160401b0381111561420857614208615d3e565b60405190808252806020026020018201604052801561423b57816020015b60608152602001906001900390816142265790505b50905060005b81518110156143155784818151811061425c5761425c6168ea565b6020026020010151516000146142cc5784818151811061427e5761427e6168ea565b60200260200101518051906020012084828151811061429f5761429f6168ea565b60200260200101516040516020016142b8929190616c83565b6040516020818303038152906040526142e7565b8381815181106142de576142de6168ea565b60200260200101515b8282815181106142f9576142f96168ea565b60200260200101819052508061430e90616916565b9050614241565b509392505050565b600063288ace0360e11b6318df743f60e31b63bf26d89760e01b6379dd796f60e01b6001600160e01b0319861682148061436357506001600160e01b0319868116908216145b8061437a57506001600160e01b0319868116908516145b8061439557506001600160e01b03198616630271189760e51b145b80611b3657506301ffc9a760e01b6001600160e01b03198716149695505050505050565b6000610ece615034565b6000807f7fffffffffffffffffffffffffffffff5d576e7357a4501ddfe92f46681b20a08311156143fa575060009050600361447e565b6040805160008082526020820180845289905260ff881692820192909252606081018690526080810185905260019060a0016020604051602081039080840390855afa15801561444e573d6000803e3d6000fd5b5050604051601f1901519150506001600160a01b0381166144775760006001925092505061447e565b9150600090505b94509492505050565b600081600481111561449b5761449b616306565b036144a35750565b60018160048111156144b7576144b7616306565b036145045760405162461bcd60e51b815260206004820152601860248201527f45434453413a20696e76616c6964207369676e617475726500000000000000006044820152606401610448565b600281600481111561451857614518616306565b036145655760405162461bcd60e51b815260206004820152601f60248201527f45434453413a20696e76616c6964207369676e6174757265206c656e677468006044820152606401610448565b600381600481111561457957614579616306565b036111af5760405162461bcd60e51b815260206004820152602260248201527f45434453413a20696e76616c6964207369676e6174757265202773272076616c604482015261756560f01b6064820152608401610448565b6000806145e187878787876150a8565b600088815261029060205260409020549091506001600160401b031615801561460e575061460e876151fe565b15611b3657600061462861028f546001600160401b031690565b614630611fc0565b65ffffffffffff166146429190616cb4565b905061464d886128ed565b816001600160401b0316111561469c576040516001600160401b038216815288907f541f725fb9f7c98a30cc9c0ff32fbb14358cd7159c847a3aa20a2bdc442ba5119060200160405180910390a25b600088815261029060205260409020805467ffffffffffffffff19166001600160401b03929092169190911790559695505050505050565b60006001600160e01b0382111561394e5760405162461bcd60e51b815260206004820152602760248201527f53616665436173743a2076616c756520646f65736e27742066697420696e20326044820152663234206269747360c81b6064820152608401610448565b60008061474b85858561523e565b915091505b935093915050565b8154600160801b90819004600f0b6000818152600180860160205260409091209390935583546001600160801b03908116939091011602179055565b61022b5460405163e38335e560e01b81526001600160a01b039091169063e38335e59034906147d0908890889088906000908990600401616b41565b6000604051808303818588803b1580156147e957600080fd5b505af11580156147fd573d6000803e3d6000fd5b50505050505050505050565b600081815261016360205260408120600281015460ff161561482e5750600792915050565b6002810154610100900460ff16156148495750600292915050565b600083815261016360205260408120546001600160401b0316908190036148b25760405162461bcd60e51b815260206004820152601d60248201527f476f7665726e6f723a20756e6b6e6f776e2070726f706f73616c2069640000006044820152606401610448565b60006148bc611fc0565b65ffffffffffff1690508082106148d857506000949350505050565b60006148e3866128ed565b90508181106148f85750600195945050505050565b614901866151fe565b8015614924575060008681526101c6602052604090206006810154600590910154115b156149355750600495945050505050565b50600395945050505050565b6000611327858585856153dd565b60008160000361496157506000919050565b6000600161496e84615493565b901c6001901b9050600181848161498757614987616a16565b048201901c9050600181848161499f5761499f616a16565b048201901c905060018184816149b7576149b7616a16565b048201901c905060018184816149cf576149cf616a16565b048201901c905060018184816149e7576149e7616a16565b048201901c905060018184816149ff576149ff616a16565b048201901c90506001818481614a1757614a17616a16565b048201901c905061204481828581614a3157614a31616a16565b04615527565b60005b81831015614315576000614a4e8484615536565b60008781526020902090915063ffffffff86169082015463ffffffff161115614a7957809250614a87565b614a84816001616be7565b93505b50614a3a565b600033614a9a8184615551565b614ae65760405162461bcd60e51b815260206004820152601d60248201527f476f7665726e6f723a2070726f706f73657220726573747269637465640000006044820152606401610448565b6000614af0611fc0565b65ffffffffffff169050614b026128e1565b614b1183610e14600185616a03565b1015614b795760405162461bcd60e51b815260206004820152603160248201527f476f7665726e6f723a2070726f706f73657220766f7465732062656c6f7720706044820152701c9bdc1bdcd85b081d1a1c995cda1bdb19607a1b6064820152608401610448565b6000614b8e8888888880519060200120612a08565b90508651885114614bb15760405162461bcd60e51b815260040161044890616cd4565b8551885114614bd25760405162461bcd60e51b815260040161044890616cd4565b6000885111614c235760405162461bcd60e51b815260206004820152601860248201527f476f7665726e6f723a20656d7074792070726f706f73616c00000000000000006044820152606401610448565b600081815261016360205260409020546001600160401b031615614c935760405162461bcd60e51b815260206004820152602160248201527f476f7665726e6f723a2070726f706f73616c20616c72656164792065786973746044820152607360f81b6064820152608401610448565b6000614c9f6101945490565b614ca99084616be7565b90506000614cb76101955490565b614cc19083616be7565b90506040518060e00160405280614cd784615642565b6001600160401b031681526001600160a01b038716602082015260006040820152606001614d0483615642565b6001600160401b03908116825260006020808401829052604080850183905260609485018390528883526101638252918290208551815492870151878501519186166001600160e01b031990941693909317600160401b6001600160a01b039094168402176001600160e01b0316600160e01b60e09290921c91909102178155938501516080860151908416921c0217600183015560a08301516002909201805460c09094015161ffff1990941692151561ff00191692909217610100931515939093029290921790558a517f7d84a6263ae0d98d3329bd7b46bb4e8d6f98cd35a7adb45c274c8b7fd5ebd5e091859188918e918e91811115614e0957614e09615d3e565b604051908082528060200260200182016040528015614e3c57816020015b6060815260200190600190039081614e275790505b508d88888f604051614e5699989796959493929190616d15565b60405180910390a1509098975050505050505050565b600054610100900460ff16614e935760405162461bcd60e51b815260040161044890616c1c565b609a614e9f8382616df3565b50609b614eac8282616df3565b50506000609881905560995550565b600054610100900460ff16614ee25760405162461bcd60e51b815260040161044890616c1c565b610162614eef8282616df3565b5050565b600054610100900460ff16614f1a5760405162461bcd60e51b815260040161044890616c1c565b614f2383613a05565b614f2c82613f18565b613be481613fbb565b600054610100900460ff16614f5c5760405162461bcd60e51b815260040161044890616c1c565b6101f880546001600160a01b0319166001600160a01b0392909216919091179055565b600054610100900460ff166120f75760405162461bcd60e51b815260040161044890616c1c565b600054610100900460ff166111a65760405162461bcd60e51b815260040161044890616c1c565b600054610100900460ff16612ac15760405162461bcd60e51b815260040161044890616c1c565b60008183116150035781612044565b5090919050565b81511561501a5781518083602001fd5b8060405162461bcd60e51b81526004016104489190615ef7565b60007f8b73c3c69bb8fe3d512ecc4cf759cc79239f7b179b0ffacaa9a75d522b39400f61505f6156aa565b615067615703565b60408051602081019490945283019190915260608201524660808201523060a082015260c00160405160208183030381529060405280519060200120905090565b60008581526101636020526040812060016150c288611751565b60078111156150d3576150d3616306565b1461512c5760405162461bcd60e51b815260206004820152602360248201527f476f7665726e6f723a20766f7465206e6f742063757272656e746c792061637460448201526269766560e81b6064820152608401610448565b80546000906151469088906001600160401b031686613da8565b90506151558888888488615734565b83516000036151aa57866001600160a01b03167fb8e138887d0aa13bab447e82de9d5c1777041ecd21ca36ba824ff1e6c07ddda48988848960405161519d9493929190616eb2565b60405180910390a2611746565b866001600160a01b03167fe2babfbac5889a709b63bb7f598b324e08bc5a4fb9ec647fb3cbc9ec07eb871289888489896040516151eb959493929190616eda565b60405180910390a2979650505050505050565b60008181526101c6602052604081206005810154615235610e8085600090815261016360205260409020546001600160401b031690565b11159392505050565b82546000908190801561538457600061525c876139d4600185616a03565b60408051808201909152905463ffffffff808216808452600160201b9092046001600160e01b0316602084015291925090871610156152dd5760405162461bcd60e51b815260206004820152601b60248201527f436865636b706f696e743a2064656372656173696e67206b65797300000000006044820152606401610448565b805163ffffffff80881691160361532557846152fe886139d4600186616a03565b80546001600160e01b0392909216600160201b0263ffffffff909216919091179055615374565b6040805180820190915263ffffffff80881682526001600160e01b0380881660208085019182528b54600181018d5560008d81529190912094519151909216600160201b029216919091179101555b6020015192508391506147509050565b50506040805180820190915263ffffffff80851682526001600160e01b0380851660208085019182528854600181018a5560008a815291822095519251909316600160201b029190931617920191909155905081614750565b6000806153ec868686866158d2565b600081815261022c6020526040902054909150156113275761022b54600082815261022c60205260409081902054905163c4d252f560e01b81526001600160a01b039092169163c4d252f5916154489160040190815260200190565b600060405180830381600087803b15801561546257600080fd5b505af1158015615476573d6000803e3d6000fd5b505050600082815261022c60205260408120555095945050505050565b600080608083901c156154a857608092831c92015b604083901c156154ba57604092831c92015b602083901c156154cc57602092831c92015b601083901c156154de57601092831c92015b600883901c156154f057600892831c92015b600483901c1561550257600492831c92015b600283901c1561551457600292831c92015b600183901c15610f995760010192915050565b60008183106150035781612044565b60006155456002848418616a2c565b61204490848416616be7565b80516000906034811015615569576001915050610f99565b82810160131901516001600160a01b031981166b046e0e4dee0dee6cae47a60f60a31b1461559c57600192505050610f99565b6000806155aa602885616a03565b90505b83811015615621576000806155e18884815181106155cd576155cd6168ea565b01602001516001600160f81b0319166159df565b91509150816155f95760019650505050505050610f99565b8060ff166004856001600160a01b0316901b17935050508061561a90616916565b90506155ad565b50856001600160a01b0316816001600160a01b031614935050505092915050565b60006001600160401b0382111561394e5760405162461bcd60e51b815260206004820152602660248201527f53616665436173743a2076616c756520646f65736e27742066697420696e203660448201526534206269747360d01b6064820152608401610448565b6000806156b5613d23565b8051909150156156cc578051602090910120919050565b60985480156156db5792915050565b7fc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a4709250505090565b60008061570e613d32565b805190915015615725578051602090910120919050565b60995480156156db5792915050565b60008581526101c6602090815260408083206001600160a01b038816845260088101909252909120805460ff16156157c45760405162461bcd60e51b815260206004820152602d60248201527f476f7665726e6f72436f6d7061746962696c697479427261766f3a20766f746560448201526c08185b1c9958591e4818d85cdd609a1b6064820152608401610448565b805460ff86166101000261ffff199091161760011781556157e484615a71565b81546001600160601b039190911662010000026dffffffffffffffffffffffff00001990911617815560ff851661583457838260060160008282546158299190616be7565b909155506129ff9050565b60001960ff86160161585457838260050160008282546158299190616be7565b60011960ff86160161587457838260070160008282546158299190616be7565b60405162461bcd60e51b815260206004820152602d60248201527f476f7665726e6f72436f6d7061746962696c697479427261766f3a20696e766160448201526c6c696420766f7465207479706560981b6064820152608401610448565b6000806158e186868686612a08565b905060006158ee82611751565b9050600281600781111561590457615904616306565b141580156159245750600681600781111561592157615921616306565b14155b80156159425750600781600781111561593f5761593f616306565b14155b61598e5760405162461bcd60e51b815260206004820152601d60248201527f476f7665726e6f723a2070726f706f73616c206e6f74206163746976650000006044820152606401610448565b6000828152610163602052604090819020600201805461ff001916610100179055517f789cf55be980739dad1d0699b93b58e806b51c9d96619bfa8fe0a28abaa7b30c9061324d9084815260200190565b60008060f883901c602f811180156159fa5750603a8160ff16105b15615a0f57600194602f199091019350915050565b8060ff166040108015615a25575060478160ff16105b15615a3a576001946036199091019350915050565b8060ff166060108015615a50575060678160ff16105b15615a65576001946056199091019350915050565b50600093849350915050565b60006001600160601b0382111561394e5760405162461bcd60e51b815260206004820152602660248201527f53616665436173743a2076616c756520646f65736e27742066697420696e203960448201526536206269747360d01b6064820152608401610448565b828054828255906000526020600020908101928215615b2e579160200282015b82811115615b2e57825182546001600160a01b0319166001600160a01b03909116178255602090920191600190910190615af9565b5061394e929150615c19565b828054828255906000526020600020908101928215615b2e579160200282015b82811115615b2e578251825591602001919060010190615b5a565b828054828255906000526020600020908101928215615bbb579160200282015b82811115615bbb5782518290615bab9082616df3565b5091602001919060010190615b95565b5061394e929150615c2e565b828054828255906000526020600020908101928215615c0d579160200282015b82811115615c0d5782518290615bfd9082616df3565b5091602001919060010190615be7565b5061394e929150615c4b565b5b8082111561394e5760008155600101615c1a565b8082111561394e576000615c428282615c68565b50600101615c2e565b8082111561394e576000615c5f8282615c68565b50600101615c4b565b508054615c74906168b0565b6000825580601f10615c84575050565b601f0160209004906000526020600020908101906111af9190615c19565b600060208284031215615cb457600080fd5b5035919050565b600060208284031215615ccd57600080fd5b81356001600160e01b03198116811461204457600080fd5b803560ff8116811461193957600080fd5b60008083601f840112615d0857600080fd5b5081356001600160401b03811115615d1f57600080fd5b602083019150836020828501011115615d3757600080fd5b9250929050565b634e487b7160e01b600052604160045260246000fd5b604051601f8201601f191681016001600160401b0381118282101715615d7c57615d7c615d3e565b604052919050565b60006001600160401b03821115615d9d57615d9d615d3e565b50601f01601f191660200190565b600082601f830112615dbc57600080fd5b8135615dcf615dca82615d84565b615d54565b818152846020838601011115615de457600080fd5b816020850160208301376000918101602001919091529392505050565b60008060008060008060008060e0898b031215615e1d57600080fd5b88359750615e2d60208a01615ce5565b965060408901356001600160401b0380821115615e4957600080fd5b615e558c838d01615cf6565b909850965060608b0135915080821115615e6e57600080fd5b50615e7b8b828c01615dab565b945050615e8a60808a01615ce5565b925060a0890135915060c089013590509295985092959890939650565b60005b83811015615ec2578181015183820152602001615eaa565b50506000910152565b60008151808452615ee3816020860160208601615ea7565b601f01601f19169290920160200192915050565b6020815260006120446020830184615ecb565b6001600160a01b03811681146111af57600080fd5b60008060008060808587031215615f3557600080fd5b8435615f4081615f0a565b93506020850135615f5081615f0a565b92506040850135915060608501356001600160401b03811115615f7257600080fd5b615f7e87828801615dab565b91505092959194509250565b60006001600160401b03821115615fa357615fa3615d3e565b5060051b60200190565b600082601f830112615fbe57600080fd5b81356020615fce615dca83615f8a565b82815260059290921b84018101918181019086841115615fed57600080fd5b8286015b8481101561601157803561600481615f0a565b8352918301918301615ff1565b509695505050505050565b600082601f83011261602d57600080fd5b8135602061603d615dca83615f8a565b82815260059290921b8401810191818101908684111561605c57600080fd5b8286015b848110156160115780358352918301918301616060565b600082601f83011261608857600080fd5b81356020616098615dca83615f8a565b82815260059290921b840181019181810190868411156160b757600080fd5b8286015b848110156160115780356001600160401b038111156160da5760008081fd5b6160e88986838b0101615dab565b8452509183019183016160bb565b6000806000806080858703121561610c57600080fd5b84356001600160401b038082111561612357600080fd5b61612f88838901615fad565b9550602087013591508082111561614557600080fd5b6161518883890161601c565b9450604087013591508082111561616757600080fd5b5061617487828801616077565b949793965093946060013593505050565b60006020828403121561619757600080fd5b813561204481615f0a565b600081518084526020808501945080840160005b838110156161db5781516001600160a01b0316875295820195908201906001016161b6565b509495945050505050565b600081518084526020808501945080840160005b838110156161db578151875295820195908201906001016161fa565b600081518084526020808501808196508360051b8101915082860160005b8581101561625e57828403895261624c848351615ecb565b98850198935090840190600101616234565b5091979650505050505050565b60808152600061627e60808301876161a2565b828103602084015261629081876161e6565b905082810360408401526162a48186616216565b905082810360608401526117468185616216565b600080600080600060a086880312156162d057600080fd5b853594506162e060208701615ce5565b93506162ee60408701615ce5565b94979396509394606081013594506080013592915050565b634e487b7160e01b600052602160045260246000fd5b602081016008831061633e57634e487b7160e01b600052602160045260246000fd5b91905290565b6000806040838503121561635757600080fd5b82359150602083013561636981615f0a565b809150509250929050565b6000806040838503121561638757600080fd5b8235915061639760208401615ce5565b90509250929050565b6000806000806000608086880312156163b857600080fd5b853594506163c860208701615ce5565b935060408601356001600160401b03808211156163e457600080fd5b6163f089838a01615cf6565b9095509350606088013591508082111561640957600080fd5b5061641688828901615dab565b9150509295509295909350565b6000806000806060858703121561643957600080fd5b8435935061644960208601615ce5565b925060408501356001600160401b0381111561646457600080fd5b61647087828801615cf6565b95989497509550505050565b6000806000806080858703121561649257600080fd5b84356001600160401b03808211156164a957600080fd5b6164b588838901615fad565b955060208701359150808211156164cb57600080fd5b6164d78883890161601c565b945060408701359150808211156164ed57600080fd5b6164f988838901616077565b9350606087013591508082111561650f57600080fd5b50615f7e87828801615dab565b60ff60f81b8816815260e06020820152600061653b60e0830189615ecb565b828103604084015261654d8189615ecb565b606084018890526001600160a01b038716608085015260a0840186905283810360c0850152905061108981856161e6565b60008060006060848603121561659357600080fd5b833561659e81615f0a565b92506020840135915060408401356001600160401b038111156165c057600080fd5b6165cc86828701615dab565b9150509250925092565b600080600080604085870312156165ec57600080fd5b84356001600160401b038082111561660357600080fd5b61660f88838901615cf6565b9096509450602087013591508082111561662857600080fd5b5061647087828801615cf6565b600080600080600060a0868803121561664d57600080fd5b853561665881615f0a565b9450602086013561666881615f0a565b935060408601356001600160401b038082111561668457600080fd5b61669089838a0161601c565b945060608801359150808211156166a657600080fd5b6166b289838a0161601c565b9350608088013591508082111561640957600080fd5b600080600080606085870312156166de57600080fd5b84356166e981615f0a565b93506020850135925060408501356001600160401b0381111561646457600080fd5b60006020828403121561671d57600080fd5b81356001600160401b038116811461204457600080fd5b600080600080600060a0868803121561674c57600080fd5b85356001600160401b038082111561676357600080fd5b61676f89838a01615fad565b9650602088013591508082111561678557600080fd5b61679189838a0161601c565b955060408801359150808211156167a757600080fd5b6167b389838a01616077565b945060608801359150808211156167c957600080fd5b6166b289838a01616077565b600080604083850312156167e857600080fd5b82356167f381615f0a565b946020939093013593505050565b600080600080600060a0868803121561681957600080fd5b853561682481615f0a565b9450602086013561683481615f0a565b9350604086013592506060860135915060808601356001600160401b0381111561685d57600080fd5b61641688828901615dab565b8183823760009101908152919050565b60208082526018908201527f476f7665726e6f723a206f6e6c79476f7665726e616e63650000000000000000604082015260600190565b600181811c908216806168c457607f821691505b6020821081036168e457634e487b7160e01b600052602260045260246000fd5b50919050565b634e487b7160e01b600052603260045260246000fd5b634e487b7160e01b600052601160045260246000fd5b60006001820161692857616928616900565b5060010190565b65ffffffffffff82811682821603908082111561694e5761694e616900565b5092915050565b60208082526021908201527f476f7665726e6f723a2070726f706f73616c206e6f74207375636365737366756040820152601b60fa1b606082015260800190565b6000602082840312156169a857600080fd5b81516001600160401b038111156169be57600080fd5b8201601f810184136169cf57600080fd5b80516169dd615dca82615d84565b8181528560208385010111156169f257600080fd5b611327826020830160208601615ea7565b81810381811115610f9957610f99616900565b634e487b7160e01b600052601260045260246000fd5b600082616a4957634e487b7160e01b600052601260045260246000fd5b500490565b600060208284031215616a6057600080fd5b815165ffffffffffff8116811461204457600080fd5b600060208284031215616a8857600080fd5b5051919050565b81835281816020850137506000828201602090810191909152601f909101601f19169091010190565b604081526000616acc604083018688616a8f565b8281036020840152611746818587616a8f565b608081526000616af260808301876161a2565b8281036020840152616b0481876161e6565b90508281036040840152616b188186616216565b91505082606083015295945050505050565b8082028115828204841417610f9957610f99616900565b60a081526000616b5460a08301886161a2565b8281036020840152616b6681886161e6565b90508281036040840152616b7a8187616216565b60608401959095525050608001529392505050565b60c081526000616ba260c08301896161a2565b8281036020840152616bb481896161e6565b90508281036040840152616bc88188616216565b60608401969096525050608081019290925260a0909101529392505050565b80820180821115610f9957610f99616900565b600060208284031215616c0c57600080fd5b8151801515811461204457600080fd5b6020808252602b908201527f496e697469616c697a61626c653a20636f6e7472616374206973206e6f74206960408201526a6e697469616c697a696e6760a81b606082015260800190565b60008251616c79818460208701615ea7565b9190910192915050565b6001600160e01b0319831681528151600090616ca6816004850160208701615ea7565b919091016004019392505050565b6001600160401b0381811683821601908082111561694e5761694e616900565b60208082526021908201527f476f7665726e6f723a20696e76616c69642070726f706f73616c206c656e67746040820152600d60fb1b606082015260800190565b8981526001600160a01b038916602082015261012060408201819052600090616d408382018b6161a2565b90508281036060840152616d54818a6161e6565b90508281036080840152616d688189616216565b905082810360a0840152616d7c8188616216565b90508560c08401528460e0840152828103610100840152616d9d8185615ecb565b9c9b505050505050505050505050565b601f821115613be457600081815260208120601f850160051c81016020861015616dd45750805b601f850160051c820191505b8181101561177f57828155600101616de0565b81516001600160401b03811115616e0c57616e0c615d3e565b616e2081616e1a84546168b0565b84616dad565b602080601f831160018114616e555760008415616e3d5750858301515b600019600386901b1c1916600185901b17855561177f565b600085815260208120601f198616915b82811015616e8457888601518255948401946001909101908401616e65565b5085821015616ea25787850151600019600388901b60f8161c191681555b5050505050600190811b01905550565b84815260ff84166020820152826040820152608060608201526000611b366080830184615ecb565b85815260ff8516602082015283604082015260a060608201526000616f0260a0830185615ecb565b8281036080840152611c4f8185615ecb56fe476f7665726e6f723a2072656c617920726576657274656420776974686f7574206d657373616765a164736f6c6343000811000a \ No newline at end of file diff --git a/core/systemcontracts/pasteur/chapel/StakeHubContract b/core/systemcontracts/pasteur/chapel/StakeHubContract new file mode 100644 index 0000000000..67153989c0 --- /dev/null +++ b/core/systemcontracts/pasteur/chapel/StakeHubContract @@ -0,0 +1 @@ +6080604052600436106200043b5760003560e01c806386d545061162000233578063ca47908f116200012f578063dd42a1dd11620000b9578063f1f74d841162000084578063f1f74d841462000d75578063f80a34021462000d8d578063fb50b31f1462000db2578063fc0c5ff11462000dd7578063ff69ab611462000def57600080fd5b8063dd42a1dd1462000ce2578063e8f67c3b1462000d09578063e992aaf51462000d21578063efdbf0e11462000d3957600080fd5b8063d7c2dfc811620000fa578063d7c2dfc81462000c68578063d8ca511f1462000c8d578063daacdb661462000ca5578063dbda7fb31462000cbd57600080fd5b8063ca47908f1462000bd1578063cbb04d9d1462000be9578063d115a2061462000c2a578063d6ca429d1462000c4357600080fd5b8063b187bd2611620001bd578063bfff04751162000188578063bfff04751462000b58578063c166f58a1462000b7d578063c38fbec81462000b94578063c473318f1462000bb9578063c8509d81146200095157600080fd5b8063b187bd261462000ac5578063baa7199e1462000ae5578063bdceadf31462000b0a578063bff02e201462000b2257600080fd5b8063a1832e6411620001fe578063a1832e641462000a22578063a43569b31462000a47578063aad3ec961462000a7b578063ac4317511462000aa057600080fd5b806386d54506146200098e5780638a4d3fa814620009c85780638cd22b2214620009e6578063982ef0a71462000a0b57600080fd5b80634838d165116200034357806364028fbd11620002cd57806375cc7d89116200029857806375cc7d8914620008fc57806376e7d6d614620009215780638129fc1c1462000939578063831d65d114620009515780638456cb59146200097657600080fd5b806364028fbd1462000837578063663706d3146200084e5780636ec01b27146200087f5780636f8e2fa414620008d757600080fd5b80634e6fd6c4116200030e5780634e6fd6c4146200079e5780635949187114620007b65780635e7cc1c914620007db57806363a036b5146200080057600080fd5b80634838d16514620006ea57806349f41a42146200072f5780634a49ac4c14620007545780634d99dd16146200077957600080fd5b80631fab701511620003c5578063384099881162000390578063384099881462000663578063417c73a7146200067b578063449ecfe614620006a057806345211bfd14620006c557600080fd5b80631fab701514620005aa5780632b727c8614620005cf5780632e8e8c7114620005f4578063367dad49146200062e57600080fd5b80630e9fbf5111620004065780630e9fbf5114620004f35780631182b875146200051857806317b4f353146200054c5780631fa8882b146200059157600080fd5b8063046f7da2146200045b578063059ddd2214620004735780630661806e14620004b5578063092193ab14620004dc57600080fd5b36620004565760345460ff166001146200045457600080fd5b005b600080fd5b3480156200046857600080fd5b506200045462000e07565b3480156200048057600080fd5b506200049862000492366004620097cc565b62000e99565b6040516001600160a01b0390911681526020015b60405180910390f35b348015620004c257600080fd5b50620004cd60365481565b604051908152602001620004ac565b62000454620004ed366004620097cc565b620012c1565b3480156200050057600080fd5b5062000454620005123660046200982e565b62001912565b3480156200052557600080fd5b506200053d6200053736600462009873565b62001c9e565b604051620004ac919062009926565b3480156200055957600080fd5b50620004986200056b366004620099f8565b80516020818301810180516045825292820191909301209152546001600160a01b031681565b3480156200059e57600080fd5b50620004cd6201518081565b348015620005b757600080fd5b5062000454620005c936600462009a94565b62001d36565b348015620005dc57600080fd5b5062000498620005ee366004620097cc565b6200208d565b3480156200060157600080fd5b506200049862000613366004620097cc565b604d602052600090815260409020546001600160a01b031681565b3480156200063b57600080fd5b50620006536200064d36600462009a94565b620020e2565b604051620004ac92919062009b13565b3480156200067057600080fd5b50620004cd60375481565b3480156200068857600080fd5b50620004546200069a366004620097cc565b620026b1565b348015620006ad57600080fd5b5062000454620006bf366004620097cc565b62002733565b348015620006d257600080fd5b5062000454620006e4366004620097cc565b62002918565b348015620006f757600080fd5b506200071e62000709366004620097cc565b60016020526000908152604090205460ff1681565b6040519015158152602001620004ac565b3480156200073c57600080fd5b50620004546200074e366004620097cc565b62002af1565b3480156200076157600080fd5b506200045462000773366004620097cc565b62002d0d565b3480156200078657600080fd5b50620004546200079836600462009bb2565b62002d89565b348015620007ab57600080fd5b506200049861dead81565b348015620007c357600080fd5b5062000454620007d536600462009bf0565b620033b9565b348015620007e857600080fd5b5062000454620007fa36600462009c5a565b620041b2565b3480156200080d57600080fd5b50620008256200081f36600462009c81565b620043dc565b604051620004ac949392919062009ca4565b620004546200084836600462009d60565b62004a81565b3480156200085b57600080fd5b50620004cd6200086d366004620097cc565b60446020526000908152604090205481565b3480156200088c57600080fd5b50620008a46200089e366004620097cc565b620050d0565b6040805182516001600160401b0390811682526020808501518216908301529282015190921690820152606001620004ac565b348015620008e457600080fd5b506200053d620008f6366004620097cc565b62005175565b3480156200090957600080fd5b50620004546200091b366004620097cc565b620055a1565b3480156200092e57600080fd5b50620004cd603d5481565b3480156200094657600080fd5b506200045462005773565b3480156200095e57600080fd5b50620004546200097036600462009873565b6200593e565b3480156200098357600080fd5b50620004546200599c565b3480156200099b57600080fd5b5062000498620009ad366004620097cc565b6043602052600090815260409020546001600160a01b031681565b348015620009d557600080fd5b50620004cd670de0b6b3a764000081565b348015620009f357600080fd5b50620004cd62000a0536600462009bb2565b62005a34565b6200045462000a1c36600462009e36565b62005aed565b34801562000a2f57600080fd5b506200045462000a4136600462009a94565b6200619b565b34801562000a5457600080fd5b5062000a6c62000a66366004620097cc565b620064a1565b604051620004ac919062009e6e565b34801562000a8857600080fd5b506200045462000a9a36600462009bb2565b6200678e565b34801562000aad57600080fd5b506200045462000abf36600462009eeb565b620067fb565b34801562000ad257600080fd5b5060005462010000900460ff166200071e565b34801562000af257600080fd5b506200045462000b0436600462009f5d565b620077ad565b34801562000b1757600080fd5b50620004cd603c5481565b34801562000b2f57600080fd5b5062000b4762000b4136600462009c81565b6200797a565b604051620004ac9392919062009fb6565b34801562000b6557600080fd5b50620004cd62000b77366004620097cc565b62007b56565b34801562000b8a57600080fd5b50620004cd600581565b34801562000ba157600080fd5b506200045462000bb3366004620097cc565b62007ba4565b34801562000bc657600080fd5b50620004cd60385481565b34801562000bde57600080fd5b50620004cd604e5481565b34801562000bf657600080fd5b5062000c0e62000c08366004620097cc565b62007ec6565b60408051938452911515602084015290820152606001620004ac565b34801562000c3757600080fd5b50620004cd620186a081565b34801562000c5057600080fd5b506200045462000c623660046200a013565b62008309565b34801562000c7557600080fd5b506200045462000c873660046200a0fc565b6200852f565b34801562000c9a57600080fd5b50620004cd603b5481565b34801562000cb257600080fd5b50620004cd60495481565b34801562000cca57600080fd5b506200049862000cdc366004620097cc565b62008625565b34801562000cef57600080fd5b50600054630100000090046001600160a01b031662000498565b34801562000d1657600080fd5b50620004cd60355481565b34801562000d2e57600080fd5b50620004cd603a5481565b34801562000d4657600080fd5b50620004cd62000d58366004620099f8565b805160208183018101805160468252928201919093012091525481565b34801562000d8257600080fd5b50620004cd603e5481565b34801562000d9a57600080fd5b50620004cd62000dac36600462009bb2565b62008a4f565b34801562000dbf57600080fd5b506200045462000dd136600462009eeb565b62008ac0565b34801562000de457600080fd5b50620004cd60395481565b34801562000dfc57600080fd5b50620004cd604a5481565b600054630100000090046001600160a01b0316331462000e3a576040516306fbb1e360e01b815260040160405180910390fd5b60005462010000900460ff1662000e6457604051636cd6020160e01b815260040160405180910390fd5b6000805462ff0000191681556040517f62451d457bc659158be6e6247f56ec1df424a5c7597f71c20c2bc44e0965c8f99190a1565b6001600160a01b038082166000908152604160209081526040808320815161018081018352815486168152600182015486169381019390935260028101549094169082015260038301546060820152600483018054929384939091608084019162000f04906200a162565b80601f016020809104026020016040519081016040528092919081815260200182805462000f32906200a162565b801562000f835780601f1062000f575761010080835404028352916020019162000f83565b820191906000526020600020905b81548152906001019060200180831162000f6557829003601f168201915b505050505081526020016005820160405180608001604052908160008201805462000fae906200a162565b80601f016020809104026020016040519081016040528092919081815260200182805462000fdc906200a162565b80156200102d5780601f1062001001576101008083540402835291602001916200102d565b820191906000526020600020905b8154815290600101906020018083116200100f57829003601f168201915b5050505050815260200160018201805462001048906200a162565b80601f016020809104026020016040519081016040528092919081815260200182805462001076906200a162565b8015620010c75780601f106200109b57610100808354040283529160200191620010c7565b820191906000526020600020905b815481529060010190602001808311620010a957829003601f168201915b50505050508152602001600282018054620010e2906200a162565b80601f016020809104026020016040519081016040528092919081815260200182805462001110906200a162565b8015620011615780601f10620011355761010080835404028352916020019162001161565b820191906000526020600020905b8154815290600101906020018083116200114357829003601f168201915b505050505081526020016003820180546200117c906200a162565b80601f0160208091040260200160405190810160405280929190818152602001828054620011aa906200a162565b8015620011fb5780601f10620011cf57610100808354040283529160200191620011fb565b820191906000526020600020905b815481529060010190602001808311620011dd57829003601f168201915b505050919092525050508152604080516060808201835260098501546001600160401b038082168452600160401b82048116602080860191909152600160801b9092041683850152840191909152600a84015460ff16151582840152600b84015490830152600c8301546080830152600d8301546001600160a01b031660a0830152805161026081019182905260c09092019190600e84019060139082845b8154815260200190600101908083116200129a575050509190925250509051949350505050565b3361100014620012ed57604051630f22c43960e41b815261100060048201526024015b60405180910390fd5b6001600160a01b0380821660009081526043602090815260408083205484168084526041835281842082516101808101845281548716815260018201548716948101949094526002810154909516918301919091526003840154606083015260048401805491949160808401919062001366906200a162565b80601f016020809104026020016040519081016040528092919081815260200182805462001394906200a162565b8015620013e55780601f10620013b957610100808354040283529160200191620013e5565b820191906000526020600020905b815481529060010190602001808311620013c757829003601f168201915b505050505081526020016005820160405180608001604052908160008201805462001410906200a162565b80601f01602080910402602001604051908101604052809291908181526020018280546200143e906200a162565b80156200148f5780601f1062001463576101008083540402835291602001916200148f565b820191906000526020600020905b8154815290600101906020018083116200147157829003601f168201915b50505050508152602001600182018054620014aa906200a162565b80601f0160208091040260200160405190810160405280929190818152602001828054620014d8906200a162565b8015620015295780601f10620014fd5761010080835404028352916020019162001529565b820191906000526020600020905b8154815290600101906020018083116200150b57829003601f168201915b5050505050815260200160028201805462001544906200a162565b80601f016020809104026020016040519081016040528092919081815260200182805462001572906200a162565b8015620015c35780601f106200159757610100808354040283529160200191620015c3565b820191906000526020600020905b815481529060010190602001808311620015a557829003601f168201915b50505050508152602001600382018054620015de906200a162565b80601f01602080910402602001604051908101604052809291908181526020018280546200160c906200a162565b80156200165d5780601f1062001631576101008083540402835291602001916200165d565b820191906000526020600020905b8154815290600101906020018083116200163f57829003601f168201915b505050919092525050508152604080516060808201835260098501546001600160401b038082168452600160401b82048116602080860191909152600160801b9092041683850152840191909152600a84015460ff16151582840152600b84015490830152600c8301546080830152600d8301546001600160a01b031660a0830152805161026081019182905260c09092019190600e84019060139082845b815481526020019060010190808311620016fc575050509190925250505060408101519091506001600160a01b031615806200173957508060e001515b15620017f657604051611002903490600081818185875af1925050503d806000811462001783576040519150601f19603f3d011682016040523d82523d6000602084013e62001788565b606091505b505050816001600160a01b03167ffc8bff675087dd2da069cc3fb517b9ed001e19750c0865241a5542dba1ba170d604051620017e99060208082526011908201527024a72b20a624a22fab20a624a220aa27a960791b604082015260600190565b60405180910390a2505050565b60408181015160c0830151519151632f303ebb60e11b81526001600160401b0390921660048301526001600160a01b031690635e607d769034906024016000604051808303818588803b1580156200184d57600080fd5b505af115801562001862573d6000803e3d6000fd5b5050505050816001600160a01b03167fe34918ff1c7084970068b53fd71ad6d8b04e9f15d3886cbf006443e6cdc52ea634604051620018a391815260200190565b60405180910390a26040808201519051633041949b60e01b815261200591633041949b91620018d8919086906004016200a198565b600060405180830381600087803b158015620018f357600080fd5b505af115801562001908573d6000803e3d6000fd5b5050505050505b50565b33611001146200193a57604051630f22c43960e41b81526110016004820152602401620012e4565b60005462010000900460ff16156200196557604051631785c68160e01b815260040160405180910390fd5b6000604583836040516200197b9291906200a1b2565b908152604051908190036020019020546001600160a01b03169050620019a3603f8262008cf9565b620019c15760405163056e881160e01b815260040160405180910390fd5b6001600160a01b038116600090815260416020526040812090620019e962015180426200a1d8565b604a546000828152604b60205260409020549192501162001a1d5760405163bd52fcdb60e01b815260040160405180910390fd5b6000818152604b6020526040812080546001929062001a3e9084906200a1fb565b909155505060405160469062001a5890879087906200a1b2565b90815260200160405180910390205460001415801562001aa9575042620151806046878760405162001a8c9291906200a1b2565b90815260200160405180910390205462001aa791906200a1fb565b105b1562001ac857604051631898eb6b60e01b815260040160405180910390fd5b60008062001ad885600262008d1c565b915091508162001afb57604051631b919bb160e11b815260040160405180910390fd5b6002840154603c5460405163045bc4d160e41b815260048101919091526000916001600160a01b0316906345bc4d10906024016020604051808303816000875af115801562001b4e573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019062001b7491906200a211565b905062001b82858362008da4565b84546040516335409f7f60e01b81526001600160a01b039091166004820152611000906335409f7f90602401600060405180830381600087803b15801562001bc957600080fd5b505af115801562001bde573d6000803e3d6000fd5b50505050856001600160a01b03167f6e9a2ee7aee95665e3a774a212eb11441b217e3e4656ab9563793094689aabb28383600260405162001c22939291906200a22b565b60405180910390a26002850154604051633041949b60e01b815261200591633041949b9162001c60916001600160a01b0316908a906004016200a198565b600060405180830381600087803b15801562001c7b57600080fd5b505af115801562001c90573d6000803e3d6000fd5b505050505050505050505050565b6060336120001462001cc857604051630f22c43960e41b81526120006004820152602401620012e4565b60005462010000900460ff161562001cf357604051631785c68160e01b815260040160405180910390fd5b6034805460ff1916600117905560405162461bcd60e51b815260206004820152600a60248201526919195c1c9958d85d195960b21b6044820152606401620012e4565b60005462010000900460ff161562001d6157604051631785c68160e01b815260040160405180910390fd5b3360009081526001602052604090205460ff161562001d935760405163b1d02c3d60e01b815260040160405180910390fd5b62001d9d62008e98565b62001daa603f8262008cf9565b62001dc85760405163056e881160e01b815260040160405180910390fd5b62001dd262008eff565b600082900362001df557604051636490ffd360e01b815260040160405180910390fd5b600062001e0162008e98565b6001600160a01b0381166000908152604f602052604090208054604e54929350909162001e2f86836200a1fb565b111562001e4f5760405163091af98560e21b815260040160405180910390fd5b60005b8581101562001f3557600087878381811062001e725762001e726200a266565b905060200201350362001e9857604051636490ffd360e01b815260040160405180910390fd5b600062001ea78260016200a1fb565b90505b8681101562001f1f5787878281811062001ec85762001ec86200a266565b9050602002013588888481811062001ee45762001ee46200a266565b905060200201350362001f0a57604051632205e3c760e11b815260040160405180910390fd5b8062001f16816200a27c565b91505062001eaa565b508062001f2c816200a27c565b91505062001e52565b5060005b8581101562001fd45760005b8281101562001fbe5783818154811062001f635762001f636200a266565b906000526020600020015488888481811062001f835762001f836200a266565b905060200201350362001fa957604051632205e3c760e11b815260040160405180910390fd5b8062001fb5816200a27c565b91505062001f45565b508062001fcb816200a27c565b91505062001f39565b5060005b8581101562001908578287878381811062001ff75762001ff76200a266565b835460018101855560009485526020948590209190940292909201359190920155506001600160a01b0384167f7c4ff4c9a343a2daef608f3b5a91016e994a15fc0ef8611109e4f45823249f298888848181106200205957620020596200a266565b905060200201356040516200207091815260200190565b60405180910390a28062002084816200a27c565b91505062001fd8565b6000816200209d603f8262008cf9565b620020bb5760405163056e881160e01b815260040160405180910390fd5b6001600160a01b038084166000908152604160205260409020600d01541691505b50919050565b60608082806001600160401b038111156200210157620021016200993b565b6040519080825280602002602001820160405280156200212b578160200160208202803683370190505b509250806001600160401b038111156200214957620021496200993b565b6040519080825280602002602001820160405280156200217e57816020015b6060815260200190600190039081620021685790505b50915060005b81811015620026a7576000868683818110620021a457620021a46200a266565b9050602002016020810190620021bb9190620097cc565b6001600160a01b0380821660009081526041602090815260408083208151610180810183528154861681526001820154861693810193909352600281015490941690820152600383015460608201526004830180549495509193909291608084019162002228906200a162565b80601f016020809104026020016040519081016040528092919081815260200182805462002256906200a162565b8015620022a75780601f106200227b57610100808354040283529160200191620022a7565b820191906000526020600020905b8154815290600101906020018083116200228957829003601f168201915b5050505050815260200160058201604051806080016040529081600082018054620022d2906200a162565b80601f016020809104026020016040519081016040528092919081815260200182805462002300906200a162565b8015620023515780601f10620023255761010080835404028352916020019162002351565b820191906000526020600020905b8154815290600101906020018083116200233357829003601f168201915b505050505081526020016001820180546200236c906200a162565b80601f01602080910402602001604051908101604052809291908181526020018280546200239a906200a162565b8015620023eb5780601f10620023bf57610100808354040283529160200191620023eb565b820191906000526020600020905b815481529060010190602001808311620023cd57829003601f168201915b5050505050815260200160028201805462002406906200a162565b80601f016020809104026020016040519081016040528092919081815260200182805462002434906200a162565b8015620024855780601f10620024595761010080835404028352916020019162002485565b820191906000526020600020905b8154815290600101906020018083116200246757829003601f168201915b50505050508152602001600382018054620024a0906200a162565b80601f0160208091040260200160405190810160405280929190818152602001828054620024ce906200a162565b80156200251f5780601f10620024f3576101008083540402835291602001916200251f565b820191906000526020600020905b8154815290600101906020018083116200250157829003601f168201915b505050919092525050508152604080516060808201835260098501546001600160401b038082168452600160401b82048116602080860191909152600160801b9092041683850152840191909152600a84015460ff16151582840152600b84015490830152600c8301546080830152600d8301546001600160a01b031660a0830152805161026081019182905260c09092019190600e84019060139082845b815481526020019060010190808311620025be5750505050508152505090508060000151868481518110620025f757620025f76200a266565b6001600160a01b039283166020918202929092018101919091529083166000908152604f8252604090819020805482518185028101850190935280835291929091908301828280156200266a57602002820191906000526020600020905b81548152602001906001019080831162002655575b50505050508584815181106200268457620026846200a266565b6020026020010181905250505080806200269e906200a27c565b91505062002184565b50505b9250929050565b600054630100000090046001600160a01b03163314620026e4576040516306fbb1e360e01b815260040160405180910390fd5b6001600160a01b0381166000818152600160208190526040808320805460ff1916909217909155517f7fd26be6fc92aff63f1f4409b2b2ddeb272a888031d7f55ec830485ec61941869190a250565b60005462010000900460ff16156200275e57604051631785c68160e01b815260040160405180910390fd5b3360009081526001602052604090205460ff1615620027905760405163b1d02c3d60e01b815260040160405180910390fd5b806200279e603f8262008cf9565b620027bc5760405163056e881160e01b815260040160405180910390fd5b6001600160a01b0382166000908152604160205260409020600a81015460ff16620027fa57604051634b6b857d60e01b815260040160405180910390fd5b6036546002820154604051630913db4760e01b81526001600160a01b03868116600483015290911690630913db4790602401602060405180830381865afa1580156200284a573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906200287091906200a211565b101562002890576040516317b204bf60e11b815260040160405180910390fd5b4281600b01541115620028b65760405163170cb76760e21b815260040160405180910390fd5b600a8101805460ff191690556049805460019190600090620028da9084906200a298565b90915550506040516001600160a01b038416907f9390b453426557da5ebdc31f19a37753ca04addf656d32f35232211bb2af3f1990600090a2505050565b60005462010000900460ff16156200294357604051631785c68160e01b815260040160405180910390fd5b3360009081526001602052604090205460ff1615620029755760405163b1d02c3d60e01b815260040160405180910390fd5b6200297f62008f12565b6200298c603f8262008cf9565b620029aa5760405163056e881160e01b815260040160405180910390fd5b6001600160a01b038216620029d257604051636520611b60e11b815260040160405180910390fd5b6001600160a01b03828116600090815260436020526040902054161562002a0c57604051631e6f587560e11b815260040160405180910390fd5b600062002a1862008f12565b6001600160a01b0381166000908152604160205260409020600c81015491925090429062002a4b9062015180906200a1fb565b111562002a6b57604051631f92cdbd60e11b815260040160405180910390fd5b80546001600160a01b039081166000908152604460209081526040808320429081905585548986166001600160a01b031991821681178855600c88019290925581855260439093528184208054958816959093168517909255519092917f6e4e747ca35203f16401c69805c7dd52fff67ef60b0ebc5c7fe16890530f223591a350505050565b3362002aff603f8262008cf9565b62002b1d5760405163056e881160e01b815260040160405180910390fd5b60005462010000900460ff161562002b4857604051631785c68160e01b815260040160405180910390fd5b3360009081526001602052604090205460ff161562002b7a5760405163b1d02c3d60e01b815260040160405180910390fd5b6001600160a01b038281166000908152604d6020526040902054161562002bb45760405163bebdc75760e01b815260040160405180910390fd5b62002bc1603f8362008cf9565b1562002be05760405163bebdc75760e01b815260040160405180910390fd5b336000818152604160205260409020600d01546001600160a01b03908116908416810362002c215760405163bebdc75760e01b815260040160405180910390fd5b6001600160a01b0381161562002c58576001600160a01b0381166000908152604d6020526040902080546001600160a01b03191690555b6001600160a01b038281166000908152604160205260409020600d0180546001600160a01b03191691861691821790551562002cbd576001600160a01b038481166000908152604d6020526040902080546001600160a01b0319169184169190911790555b836001600160a01b0316816001600160a01b0316836001600160a01b03167fcbb728765de145e99c00e8ae32a325231e850359b7b8a6da3b84d672ab3f1d0a60405160405180910390a450505050565b600054630100000090046001600160a01b0316331462002d40576040516306fbb1e360e01b815260040160405180910390fd5b6001600160a01b038116600081815260016020526040808220805460ff19169055517fe0db3499b7fdc3da4cddff5f45d694549c19835e7f719fb5606d3ad1a5de40119190a250565b60005462010000900460ff161562002db457604051631785c68160e01b815260040160405180910390fd5b3360009081526001602052604090205460ff161562002de65760405163b1d02c3d60e01b815260040160405180910390fd5b8162002df4603f8262008cf9565b62002e125760405163056e881160e01b815260040160405180910390fd5b8160000362002e3457604051639811e0c760e01b815260040160405180910390fd5b6001600160a01b038084166000908152604160209081526040808320815161018081018352815486168152600182015486169381019390935260028101549094169082015260038301546060820152600483018054339491608084019162002e9c906200a162565b80601f016020809104026020016040519081016040528092919081815260200182805462002eca906200a162565b801562002f1b5780601f1062002eef5761010080835404028352916020019162002f1b565b820191906000526020600020905b81548152906001019060200180831162002efd57829003601f168201915b505050505081526020016005820160405180608001604052908160008201805462002f46906200a162565b80601f016020809104026020016040519081016040528092919081815260200182805462002f74906200a162565b801562002fc55780601f1062002f995761010080835404028352916020019162002fc5565b820191906000526020600020905b81548152906001019060200180831162002fa757829003601f168201915b5050505050815260200160018201805462002fe0906200a162565b80601f01602080910402602001604051908101604052809291908181526020018280546200300e906200a162565b80156200305f5780601f1062003033576101008083540402835291602001916200305f565b820191906000526020600020905b8154815290600101906020018083116200304157829003601f168201915b505050505081526020016002820180546200307a906200a162565b80601f0160208091040260200160405190810160405280929190818152602001828054620030a8906200a162565b8015620030f95780601f10620030cd57610100808354040283529160200191620030f9565b820191906000526020600020905b815481529060010190602001808311620030db57829003601f168201915b5050505050815260200160038201805462003114906200a162565b80601f016020809104026020016040519081016040528092919081815260200182805462003142906200a162565b8015620031935780601f10620031675761010080835404028352916020019162003193565b820191906000526020600020905b8154815290600101906020018083116200317557829003601f168201915b505050919092525050508152604080516060808201835260098501546001600160401b038082168452600160401b82048116602080860191909152600160801b9092041683850152840191909152600a84015460ff16151582840152600b84015490830152600c8301546080830152600d8301546001600160a01b031660a0830152805161026081019182905260c09092019190600e84019060139082845b81548152602001906001019080831162003232575050509190925250505060408082015190516326ccee8b60e11b81526001600160a01b0385811660048301526024820188905292935060009290911690634d99dd16906044016020604051808303816000875af1158015620032ac573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190620032d291906200a211565b9050826001600160a01b0316866001600160a01b03167f3aace7340547de7b9156593a7652dc07ee900cea3fd8f82cb6c9d38b40829802878460405162003323929190918252602082015260400190565b60405180910390a3856001600160a01b0316836001600160a01b0316036200335057620033508662008f53565b6040808301519051633041949b60e01b815261200591633041949b916200337d919087906004016200a198565b600060405180830381600087803b1580156200339857600080fd5b505af1158015620033ad573d6000803e3d6000fd5b50505050505050505050565b60005462010000900460ff1615620033e457604051631785c68160e01b815260040160405180910390fd5b3360009081526001602052604090205460ff1615620034165760405163b1d02c3d60e01b815260040160405180910390fd5b8362003424603f8262008cf9565b620034425760405163056e881160e01b815260040160405180910390fd5b8362003450603f8262008cf9565b6200346e5760405163056e881160e01b815260040160405180910390fd5b6034805460ff1916600117905560008490036200349e57604051639811e0c760e01b815260040160405180910390fd5b846001600160a01b0316866001600160a01b031603620034d15760405163f0e3e62960e01b815260040160405180910390fd5b6001600160a01b038087166000908152604160209081526040808320815161018081018352815486168152600182015486169381019390935260028101549094169082015260038301546060820152600483018054339491608084019162003539906200a162565b80601f016020809104026020016040519081016040528092919081815260200182805462003567906200a162565b8015620035b85780601f106200358c57610100808354040283529160200191620035b8565b820191906000526020600020905b8154815290600101906020018083116200359a57829003601f168201915b5050505050815260200160058201604051806080016040529081600082018054620035e3906200a162565b80601f016020809104026020016040519081016040528092919081815260200182805462003611906200a162565b8015620036625780601f10620036365761010080835404028352916020019162003662565b820191906000526020600020905b8154815290600101906020018083116200364457829003601f168201915b505050505081526020016001820180546200367d906200a162565b80601f0160208091040260200160405190810160405280929190818152602001828054620036ab906200a162565b8015620036fc5780601f10620036d057610100808354040283529160200191620036fc565b820191906000526020600020905b815481529060010190602001808311620036de57829003601f168201915b5050505050815260200160028201805462003717906200a162565b80601f016020809104026020016040519081016040528092919081815260200182805462003745906200a162565b8015620037965780601f106200376a5761010080835404028352916020019162003796565b820191906000526020600020905b8154815290600101906020018083116200377857829003601f168201915b50505050508152602001600382018054620037b1906200a162565b80601f0160208091040260200160405190810160405280929190818152602001828054620037df906200a162565b8015620038305780601f10620038045761010080835404028352916020019162003830565b820191906000526020600020905b8154815290600101906020018083116200381257829003601f168201915b505050919092525050508152604080516060808201835260098501546001600160401b038082168452600160401b82048116602080860191909152600160801b9092041683850152840191909152600a84015460ff16151582840152600b84015490830152600c8301546080830152600d8301546001600160a01b031660a0830152805161026081019182905260c09092019190600e84019060139082845b815481526020019060010190808311620038cf57505050919092525050506001600160a01b038089166000908152604160209081526040808320815161018081018352815486168152600182015486169381019390935260028101549094169082015260038301546060820152600483018054949550919390929160808401916200395a906200a162565b80601f016020809104026020016040519081016040528092919081815260200182805462003988906200a162565b8015620039d95780601f10620039ad57610100808354040283529160200191620039d9565b820191906000526020600020905b815481529060010190602001808311620039bb57829003601f168201915b505050505081526020016005820160405180608001604052908160008201805462003a04906200a162565b80601f016020809104026020016040519081016040528092919081815260200182805462003a32906200a162565b801562003a835780601f1062003a575761010080835404028352916020019162003a83565b820191906000526020600020905b81548152906001019060200180831162003a6557829003601f168201915b5050505050815260200160018201805462003a9e906200a162565b80601f016020809104026020016040519081016040528092919081815260200182805462003acc906200a162565b801562003b1d5780601f1062003af15761010080835404028352916020019162003b1d565b820191906000526020600020905b81548152906001019060200180831162003aff57829003601f168201915b5050505050815260200160028201805462003b38906200a162565b80601f016020809104026020016040519081016040528092919081815260200182805462003b66906200a162565b801562003bb75780601f1062003b8b5761010080835404028352916020019162003bb7565b820191906000526020600020905b81548152906001019060200180831162003b9957829003601f168201915b5050505050815260200160038201805462003bd2906200a162565b80601f016020809104026020016040519081016040528092919081815260200182805462003c00906200a162565b801562003c515780601f1062003c255761010080835404028352916020019162003c51565b820191906000526020600020905b81548152906001019060200180831162003c3357829003601f168201915b505050919092525050508152604080516060808201835260098501546001600160401b038082168452600160401b82048116602080860191909152600160801b9092041683850152840191909152600a84015460ff16151582840152600b84015490830152600c8301546080830152600d8301546001600160a01b031660a0830152805161026081019182905260c09092019190600e84019060139082845b81548152602001906001019080831162003cf05750505050508152505090508060e00151801562003d335750876001600160a01b0316836001600160a01b031614155b1562003d5257604051636468920360e01b815260040160405180910390fd5b60408083015190516352e82ce560e11b81526001600160a01b038581166004830152602482018a9052600092169063a5d059ca906044016020604051808303816000875af115801562003da9573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019062003dcf91906200a211565b905060375481101562003df55760405163dc6f0bdd60e01b815260040160405180910390fd5b896001600160a01b0316846001600160a01b031614801562003e8a57506036546040808501519051630913db4760e01b81526001600160a01b038d8116600483015290911690630913db4790602401602060405180830381865afa15801562003e62573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019062003e8891906200a211565b105b1562003ea9576040516317b204bf60e11b815260040160405180910390fd5b6000620186a0603a548362003ebf91906200a2ae565b62003ecb91906200a1d8565b9050600083604001516001600160a01b03168260405160006040518083038185875af1925050503d806000811462003f20576040519150601f19603f3d011682016040523d82523d6000602084013e62003f25565b606091505b505090508062003f48576040516312171d8360e31b815260040160405180910390fd5b62003f5482846200a298565b60408086015190516317066a5760e21b81526001600160a01b03898116600483015292955060009290911690635c19a95c90869060240160206040518083038185885af115801562003faa573d6000803e3d6000fd5b50505050506040513d601f19601f8201168201806040525081019062003fd191906200a211565b9050866001600160a01b03168c6001600160a01b03168e6001600160a01b03167ffdac6e81913996d95abcc289e90f2d8bd235487ce6fe6f821e7d21002a1915b48e858960405162004036939291909283526020830191909152604082015260600190565b60405180910390a46040805160028082526060820183526000926020830190803683370190505090508660400151816000815181106200407a576200407a6200a266565b60200260200101906001600160a01b031690816001600160a01b031681525050856040015181600181518110620040b557620040b56200a266565b6001600160a01b0390921660209283029190910190910152604051634484077560e01b815261200590634484077590620040f69084908c906004016200a2c8565b600060405180830381600087803b1580156200411157600080fd5b505af115801562004126573d6000803e3d6000fd5b505050508a1562004198576120056001600160a01b031663e5ed5b1e898f6040518363ffffffff1660e01b8152600401620041639291906200a198565b600060405180830381600087803b1580156200417e57600080fd5b505af115801562004193573d6000803e3d6000fd5b505050505b50506034805460ff19169055505050505050505050505050565b60005462010000900460ff1615620041dd57604051631785c68160e01b815260040160405180910390fd5b3360009081526001602052604090205460ff16156200420f5760405163b1d02c3d60e01b815260040160405180910390fd5b6200421962008f12565b62004226603f8262008cf9565b620042445760405163056e881160e01b815260040160405180910390fd5b60006200425062008f12565b6001600160a01b0381166000908152604160205260409020600c810154919250904290620042839062015180906200a1fb565b1115620042a357604051631f92cdbd60e11b815260040160405180910390fd5b60098101546001600160401b03600160401b90910481169085161115620042dd5760405163dc81db8560e01b815260040160405180910390fd5b60098101546000906001600160401b0390811690861610156200431b576009820154620043159086906001600160401b03166200a2f4565b62004335565b600982015462004335906001600160401b0316866200a2f4565b60098301546001600160401b039182169250600160801b900416811115620043705760405163dc81db8560e01b815260040160405180910390fd5b60098201805467ffffffffffffffff19166001600160401b03871690811790915542600c8401556040519081526001600160a01b038416907f78cdd96edf59e09cfd4d26ef6ef6c92d166effe6a40970c54821206d541932cb9060200160405180910390a25050505050565b60608060606000620043ef603f62009071565b90508086101562004a785784156200440857846200440a565b805b94506000856200441b88846200a298565b1162004433576200442d87836200a298565b62004435565b855b9050806001600160401b038111156200445257620044526200993b565b6040519080825280602002602001820160405280156200447c578160200160208202803683370190505b509450806001600160401b038111156200449a576200449a6200993b565b604051908082528060200260200182016040528015620044c4578160200160208202803683370190505b509350806001600160401b03811115620044e257620044e26200993b565b6040519080825280602002602001820160405280156200451757816020015b6060815260200190600190039081620045015790505b50925060005b8181101562004a755760006200454162004538838b6200a1fb565b603f906200907c565b6001600160a01b03808216600090815260416020908152604080832081516101808101835281548616815260018201548616938101939093526002810154909416908201526003830154606082015260048301805494955091939092916080840191620045ae906200a162565b80601f0160208091040260200160405190810160405280929190818152602001828054620045dc906200a162565b80156200462d5780601f1062004601576101008083540402835291602001916200462d565b820191906000526020600020905b8154815290600101906020018083116200460f57829003601f168201915b505050505081526020016005820160405180608001604052908160008201805462004658906200a162565b80601f016020809104026020016040519081016040528092919081815260200182805462004686906200a162565b8015620046d75780601f10620046ab57610100808354040283529160200191620046d7565b820191906000526020600020905b815481529060010190602001808311620046b957829003601f168201915b50505050508152602001600182018054620046f2906200a162565b80601f016020809104026020016040519081016040528092919081815260200182805462004720906200a162565b8015620047715780601f10620047455761010080835404028352916020019162004771565b820191906000526020600020905b8154815290600101906020018083116200475357829003601f168201915b505050505081526020016002820180546200478c906200a162565b80601f0160208091040260200160405190810160405280929190818152602001828054620047ba906200a162565b80156200480b5780601f10620047df576101008083540402835291602001916200480b565b820191906000526020600020905b815481529060010190602001808311620047ed57829003601f168201915b5050505050815260200160038201805462004826906200a162565b80601f016020809104026020016040519081016040528092919081815260200182805462004854906200a162565b8015620048a55780601f106200487957610100808354040283529160200191620048a5565b820191906000526020600020905b8154815290600101906020018083116200488757829003601f168201915b505050919092525050508152604080516060808201835260098501546001600160401b038082168452600160401b82048116602080860191909152600160801b9092041683850152840191909152600a84015460ff16151582840152600b84015490830152600c8301546080830152600d8301546001600160a01b031660a0830152805161026081019182905260c09092019190600e84019060139082845b8154815260200190600101908083116200494457505050505081525050905080600001518884815181106200497d576200497d6200a266565b60200260200101906001600160a01b031690816001600160a01b0316815250508060e0015162004a165780604001516001600160a01b03166315d1f8986040518163ffffffff1660e01b8152600401602060405180830381865afa158015620049ea573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019062004a1091906200a211565b62004a19565b60005b87848151811062004a2e5762004a2e6200a266565b602002602001018181525050806080015186848151811062004a545762004a546200a266565b602002602001018190525050508062004a6d906200a27c565b90506200451d565b50505b92959194509250565b60005462010000900460ff161562004aac57604051631785c68160e01b815260040160405180910390fd5b3360009081526001602052604090205460ff161562004ade5760405163b1d02c3d60e01b815260040160405180910390fd5b3362004aec603f8262008cf9565b1562004b0b57604051635f28f62b60e01b815260040160405180910390fd5b6001600160a01b038181166000908152604d6020526040902054161562004b4557604051631a0a9b9f60e21b815260040160405180910390fd5b6001600160a01b03888116600090815260436020526040902054161562004b7f57604051631e6f587560e11b815260040160405180910390fd5b60006001600160a01b03166045888860405162004b9e9291906200a1b2565b908152604051908190036020019020546001600160a01b03161462004bd6576040516311fdb94760e01b815260040160405180910390fd5b600062004be483806200a31e565b60405160200162004bf79291906200a1b2565b60408051601f1981840301815291815281516020928301206000818152604290935291205490915060ff161562004c415760405163c0bf414360e01b815260040160405180910390fd5b600062004c57670de0b6b3a7640000346200a298565b905060365481101562004c7d576040516317b204bf60e11b815260040160405180910390fd5b6001600160a01b038a1662004ca557604051636520611b60e11b815260040160405180910390fd5b61138862004cba604087016020880162009c5a565b6001600160401b0316118062004d00575062004cdd604086016020870162009c5a565b6001600160401b031662004cf5602087018762009c5a565b6001600160401b0316115b8062004d3f575062004d19604086016020870162009c5a565b6001600160401b031662004d34606087016040880162009c5a565b6001600160401b0316115b1562004d5e5760405163dc81db8560e01b815260040160405180910390fd5b62004da962004d6e85806200a31e565b8080601f0160208091040260200160405190810160405280939291908181526020018383808284376000920191909152506200908a92505050565b62004dc757604051635dba5ad760e01b815260040160405180910390fd5b62004dd6838a8a8a8a6200922c565b62004df457604051631647e3cb60e11b815260040160405180910390fd5b600062004e428462004e0787806200a31e565b8080601f0160208091040260200160405190810160405280939291908181526020018383808284376000920191909152506200935c92505050565b905062004e51603f856200945d565b506000838152604260209081526040808320805460ff191660019081179091556001600160a01b0380891680865260419094529190932080548f83166001600160a01b03199182161782559381018054851690931790925560028201805491851691909316179091554260038201556004810162004ed18b8d836200a3c6565b50856005820162004ee382826200a48e565b508790506009820162004ef782826200a5c7565b505042600c8201556001600160a01b038c81166000908152604360205260409081902080546001600160a01b0319169288169290921790915551859060459062004f45908e908e906200a1b2565b908152602001604051809103902060006101000a8154816001600160a01b0302191690836001600160a01b03160217905550816001600160a01b0316856001600160a01b03168d6001600160a01b03167faecd9fb95e79c75a3a1de93362c6be5fe6ab65770d8614be583884161cd8228d8e8e60405162004fc89291906200a697565b60405180910390a460408051848152602081018590526001600160a01b0387169182917f24d7bda8602b916d64417f0dbfe2e2e88ec9b1157bd9f596dfdb91ba26624e04910160405180910390a360408051670de0b6b3a7640000808252602082015261dead916001600160a01b038816917f24d7bda8602b916d64417f0dbfe2e2e88ec9b1157bd9f596dfdb91ba26624e04910160405180910390a3604051633041949b60e01b815261200590633041949b906200508e90859089906004016200a198565b600060405180830381600087803b158015620050a957600080fd5b505af1158015620050be573d6000803e3d6000fd5b50505050505050505050505050505050565b604080516060810182526000808252602082018190529181019190915281620050fb603f8262008cf9565b620051195760405163056e881160e01b815260040160405180910390fd5b50506001600160a01b031660009081526041602090815260409182902082516060810184526009909101546001600160401b038082168352600160401b8204811693830193909352600160801b90049091169181019190915290565b6001600160a01b03808216600090815260416020908152604080832081516101808101835281548616815260018201548616938101939093526002810154909416908201526003830154606082810191909152600484018054919491608084019190620051e2906200a162565b80601f016020809104026020016040519081016040528092919081815260200182805462005210906200a162565b8015620052615780601f10620052355761010080835404028352916020019162005261565b820191906000526020600020905b8154815290600101906020018083116200524357829003601f168201915b50505050508152602001600582016040518060800160405290816000820180546200528c906200a162565b80601f0160208091040260200160405190810160405280929190818152602001828054620052ba906200a162565b80156200530b5780601f10620052df576101008083540402835291602001916200530b565b820191906000526020600020905b815481529060010190602001808311620052ed57829003601f168201915b5050505050815260200160018201805462005326906200a162565b80601f016020809104026020016040519081016040528092919081815260200182805462005354906200a162565b8015620053a55780601f106200537957610100808354040283529160200191620053a5565b820191906000526020600020905b8154815290600101906020018083116200538757829003601f168201915b50505050508152602001600282018054620053c0906200a162565b80601f0160208091040260200160405190810160405280929190818152602001828054620053ee906200a162565b80156200543f5780601f1062005413576101008083540402835291602001916200543f565b820191906000526020600020905b8154815290600101906020018083116200542157829003601f168201915b505050505081526020016003820180546200545a906200a162565b80601f016020809104026020016040519081016040528092919081815260200182805462005488906200a162565b8015620054d95780601f10620054ad57610100808354040283529160200191620054d9565b820191906000526020600020905b815481529060010190602001808311620054bb57829003601f168201915b505050919092525050508152604080516060808201835260098501546001600160401b038082168452600160401b82048116602080860191909152600160801b9092041683850152840191909152600a84015460ff16151582840152600b84015490830152600c8301546080830152600d8301546001600160a01b031660a0830152805161026081019182905260c09092019190600e84019060139082845b815481526020019060010190808311620055785750505091909252505050608001519392505050565b3361100114620055c957604051630f22c43960e41b81526110016004820152602401620012e4565b6001600160a01b0380821660009081526043602052604090205416620055f1603f8262008cf9565b6200560f5760405163056e881160e01b815260040160405180910390fd5b6001600160a01b038181166000908152604160205260408082206002810154603b54925163045bc4d160e41b81526004810193909352909316906345bc4d10906024016020604051808303816000875af115801562005672573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906200569891906200a211565b90506000603d5442620056ac91906200a1fb565b9050620056ba838262008da4565b836001600160a01b03167f6e9a2ee7aee95665e3a774a212eb11441b217e3e4656ab9563793094689aabb282846001604051620056fa939291906200a22b565b60405180910390a26002830154604051633041949b60e01b815261200591633041949b9162005738916001600160a01b03169088906004016200a198565b600060405180830381600087803b1580156200575357600080fd5b505af115801562005768573d6000803e3d6000fd5b505050505050505050565b600054610100900460ff1615808015620057945750600054600160ff909116105b80620057b05750303b158015620057b0575060005460ff166001145b620058155760405162461bcd60e51b815260206004820152602e60248201527f496e697469616c697a61626c653a20636f6e747261637420697320616c72656160448201526d191e481a5b9a5d1a585b1a5e995960921b6064820152608401620012e4565b6000805460ff19166001179055801562005839576000805461ff0019166101001790555b3341146200585a5760405163022d8c9560e31b815260040160405180910390fd5b3a156200587a576040516383f1b1d360e01b815260040160405180910390fd5b611388603555686c6b935b8bbd400000603655670de0b6b3a7640000603755600960385562093a806039556002603a819055678ac7230489e80000603b55680ad78ebc5ac6200000603c556202a300603d5562069780603e55604a55620058f57330151da466ec8ab345bef3d6983023e050fb067362009474565b80156200190f576000805461ff0019169055604051600181527f7f26b83ff96e1f2b6a682f133852f6798a09c465da95921460cefb38474024989060200160405180910390a150565b33612000146200596657604051630f22c43960e41b81526120006004820152602401620012e4565b60405162461bcd60e51b815260206004820152600a60248201526919195c1c9958d85d195960b21b6044820152606401620012e4565b600054630100000090046001600160a01b03163314620059cf576040516306fbb1e360e01b815260040160405180910390fd5b60005462010000900460ff1615620059fa57604051631785c68160e01b815260040160405180910390fd5b6000805462ff00001916620100001781556040517f9e87fac88ff661f02d44f95383c817fece4bce600a3dab7a54406878b965e7529190a1565b600062005a43603f8462008cf9565b62005a615760405163056e881160e01b815260040160405180910390fd5b6001600160a01b0383811660009081526041602052604090819020600201549051636bbf224960e01b815260048101859052911690636bbf2249906024015b602060405180830381865afa15801562005abe573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019062005ae491906200a211565b90505b92915050565b60005462010000900460ff161562005b1857604051631785c68160e01b815260040160405180910390fd5b3360009081526001602052604090205460ff161562005b4a5760405163b1d02c3d60e01b815260040160405180910390fd5b8162005b58603f8262008cf9565b62005b765760405163056e881160e01b815260040160405180910390fd5b603754349081101562005b9c5760405163dc6f0bdd60e01b815260040160405180910390fd5b6001600160a01b038085166000908152604160209081526040808320815161018081018352815486168152600182015486169381019390935260028101549094169082015260038301546060820152600483018054339491608084019162005c04906200a162565b80601f016020809104026020016040519081016040528092919081815260200182805462005c32906200a162565b801562005c835780601f1062005c575761010080835404028352916020019162005c83565b820191906000526020600020905b81548152906001019060200180831162005c6557829003601f168201915b505050505081526020016005820160405180608001604052908160008201805462005cae906200a162565b80601f016020809104026020016040519081016040528092919081815260200182805462005cdc906200a162565b801562005d2d5780601f1062005d015761010080835404028352916020019162005d2d565b820191906000526020600020905b81548152906001019060200180831162005d0f57829003601f168201915b5050505050815260200160018201805462005d48906200a162565b80601f016020809104026020016040519081016040528092919081815260200182805462005d76906200a162565b801562005dc75780601f1062005d9b5761010080835404028352916020019162005dc7565b820191906000526020600020905b81548152906001019060200180831162005da957829003601f168201915b5050505050815260200160028201805462005de2906200a162565b80601f016020809104026020016040519081016040528092919081815260200182805462005e10906200a162565b801562005e615780601f1062005e355761010080835404028352916020019162005e61565b820191906000526020600020905b81548152906001019060200180831162005e4357829003601f168201915b5050505050815260200160038201805462005e7c906200a162565b80601f016020809104026020016040519081016040528092919081815260200182805462005eaa906200a162565b801562005efb5780601f1062005ecf5761010080835404028352916020019162005efb565b820191906000526020600020905b81548152906001019060200180831162005edd57829003601f168201915b505050919092525050508152604080516060808201835260098501546001600160401b038082168452600160401b82048116602080860191909152600160801b9092041683850152840191909152600a84015460ff16151582840152600b84015490830152600c8301546080830152600d8301546001600160a01b031660a0830152805161026081019182905260c09092019190600e84019060139082845b81548152602001906001019080831162005f9a5750505050508152505090508060e00151801562005fdd5750856001600160a01b0316826001600160a01b031614155b1562005ffc57604051636468920360e01b815260040160405180910390fd5b60408082015190516317066a5760e21b81526001600160a01b0384811660048301526000921690635c19a95c90869060240160206040518083038185885af11580156200604d573d6000803e3d6000fd5b50505050506040513d601f19601f820116820180604052508101906200607491906200a211565b9050826001600160a01b0316876001600160a01b03167f24d7bda8602b916d64417f0dbfe2e2e88ec9b1157bd9f596dfdb91ba26624e048387604051620060c5929190918252602082015260400190565b60405180910390a36040808301519051633041949b60e01b815261200591633041949b91620060fa919087906004016200a198565b600060405180830381600087803b1580156200611557600080fd5b505af11580156200612a573d6000803e3d6000fd5b50505050851562001908576040516372f6ad8f60e11b81526120059063e5ed5b1e906200615e9086908b906004016200a198565b600060405180830381600087803b1580156200617957600080fd5b505af11580156200618e573d6000803e3d6000fd5b5050505050505050505050565b60005462010000900460ff1615620061c657604051631785c68160e01b815260040160405180910390fd5b3360009081526001602052604090205460ff1615620061f85760405163b1d02c3d60e01b815260040160405180910390fd5b6200620262008e98565b6200620f603f8262008cf9565b6200622d5760405163056e881160e01b815260040160405180910390fd5b60006200623962008e98565b6001600160a01b0381166000908152604f6020526040812080549293509190859003620063105760005b81811015620062e457836001600160a01b03167f08e60c1b84aab23d99a7262015e647d5ffd6c6e08f78205e1df6774c48e1427a848381548110620062ac57620062ac6200a266565b9060005260206000200154604051620062c791815260200190565b60405180910390a280620062db816200a27c565b91505062006263565b506001600160a01b0383166000908152604f60205260408120620063089162009766565b505050505050565b60005b858110156200646e5760008787838181106200633357620063336200a266565b90506020020135905060005b838110156200645657818582815481106200635e576200635e6200a266565b9060005260206000200154036200644157846200637d6001866200a298565b815481106200639057620063906200a266565b9060005260206000200154858281548110620063b057620063b06200a266565b906000526020600020018190555084805480620063d157620063d16200a6ad565b600190038181906000526020600020016000905590558380620063f4906200a6c3565b945050856001600160a01b03167f08e60c1b84aab23d99a7262015e647d5ffd6c6e08f78205e1df6774c48e1427a836040516200643391815260200190565b60405180910390a262006456565b806200644d816200a27c565b9150506200633f565b5050808062006465906200a27c565b91505062006313565b50815460000362006308576001600160a01b0383166000908152604f60205260408120620063089162009766565b505050565b620064cd6040518060800160405280606081526020016060815260200160608152602001606081525090565b81620064db603f8262008cf9565b620064f95760405163056e881160e01b815260040160405180910390fd5b6001600160a01b0383166000908152604160205260409081902081516080810190925260050180548290829062006530906200a162565b80601f01602080910402602001604051908101604052809291908181526020018280546200655e906200a162565b8015620065af5780601f106200658357610100808354040283529160200191620065af565b820191906000526020600020905b8154815290600101906020018083116200659157829003601f168201915b50505050508152602001600182018054620065ca906200a162565b80601f0160208091040260200160405190810160405280929190818152602001828054620065f8906200a162565b8015620066495780601f106200661d5761010080835404028352916020019162006649565b820191906000526020600020905b8154815290600101906020018083116200662b57829003601f168201915b5050505050815260200160028201805462006664906200a162565b80601f016020809104026020016040519081016040528092919081815260200182805462006692906200a162565b8015620066e35780601f10620066b757610100808354040283529160200191620066e3565b820191906000526020600020905b815481529060010190602001808311620066c557829003601f168201915b50505050508152602001600382018054620066fe906200a162565b80601f01602080910402602001604051908101604052809291908181526020018280546200672c906200a162565b80156200677d5780601f1062006751576101008083540402835291602001916200677d565b820191906000526020600020905b8154815290600101906020018083116200675f57829003601f168201915b505050505081525050915050919050565b60005462010000900460ff1615620067b957604051631785c68160e01b815260040160405180910390fd5b3360009081526001602052604090205460ff1615620067eb5760405163b1d02c3d60e01b815260040160405180910390fd5b620067f782826200950d565b5050565b33611007146200682357604051630f22c43960e41b81526110076004820152602401620012e4565b620068906040518060400160405280601081526020016f1d1c985b9cd9995c91d85cd31a5b5a5d60821b81525085858080601f0160208091040260200160405190810160405280939291908181526020018383808284376000920191909152509293925050620096199050565b156200694b5760208114620068c25783838383604051630a5a604160e01b8152600401620012e494939291906200a6dd565b604080516020601f840181900481028201810190925282815260009162006905918585808385018382808284376000920191909152509293925050620096769050565b90506108fc81108062006919575061271081115b15620069425784848484604051630a5a604160e01b8152600401620012e494939291906200a6dd565b60355562007768565b620069bc6040518060400160405280601481526020017336b4b729b2b6332232b632b3b0ba34b7b721272160611b81525085858080601f0160208091040260200160405190810160405280939291908181526020018383808284376000920191909152509293925050620096199050565b1562006a865760208114620069ee5783838383604051630a5a604160e01b8152600401620012e494939291906200a6dd565b604080516020601f840181900481028201810190925282815260009162006a31918585808385018382808284376000920191909152509293925050620096769050565b9050683635c9adc5dea0000081108062006a54575069152d02c7e14af680000081115b1562006a7d5784848484604051630a5a604160e01b8152600401620012e494939291906200a6dd565b60365562007768565b62006af9604051806040016040528060168152602001756d696e44656c65676174696f6e424e424368616e676560501b81525085858080601f0160208091040260200160405190810160405280939291908181526020018383808284376000920191909152509293925050620096199050565b1562006bc0576020811462006b2b5783838383604051630a5a604160e01b8152600401620012e494939291906200a6dd565b604080516020601f840181900481028201810190925282815260009162006b6e918585808385018382808284376000920191909152509293925050620096769050565b905067016345785d8a000081108062006b8e5750678ac7230489e8000081115b1562006bb75784848484604051630a5a604160e01b8152600401620012e494939291906200a6dd565b60375562007768565b62006c31604051806040016040528060148152602001736d6178456c656374656456616c696461746f727360601b81525085858080601f0160208091040260200160405190810160405280939291908181526020018383808284376000920191909152509293925050620096199050565b1562006ce9576020811462006c635783838383604051630a5a604160e01b8152600401620012e494939291906200a6dd565b604080516020601f840181900481028201810190925282815260009162006ca6918585808385018382808284376000920191909152509293925050620096769050565b905080158062006cb757506101f481115b1562006ce05784848484604051630a5a604160e01b8152600401620012e494939291906200a6dd565b60385562007768565b62006d526040518060400160405280600c81526020016b1d5b989bdb9914195c9a5bd960a21b81525085858080601f0160208091040260200160405190810160405280939291908181526020018383808284376000920191909152509293925050620096199050565b1562006e0f576020811462006d845783838383604051630a5a604160e01b8152600401620012e494939291906200a6dd565b604080516020601f840181900481028201810190925282815260009162006dc7918585808385018382808284376000920191909152509293925050620096769050565b90506203f48081108062006ddd575062278d0081115b1562006e065784848484604051630a5a604160e01b8152600401620012e494939291906200a6dd565b60395562007768565b62006e7d60405180604001604052806011815260200170726564656c65676174654665655261746560781b81525085858080601f0160208091040260200160405190810160405280939291908181526020018383808284376000920191909152509293925050620096199050565b1562006f2a576020811462006eaf5783838383604051630a5a604160e01b8152600401620012e494939291906200a6dd565b604080516020601f840181900481028201810190925282815260009162006ef2918585808385018382808284376000920191909152509293925050620096769050565b9050606481111562006f215784848484604051630a5a604160e01b8152600401620012e494939291906200a6dd565b603a5562007768565b62006f9a60405180604001604052806013815260200172191bdddb9d1a5b5954db185cda105b5bdd5b9d606a1b81525085858080601f0160208091040260200160405190810160405280939291908181526020018383808284376000920191909152509293925050620096199050565b156200705c576020811462006fcc5783838383604051630a5a604160e01b8152600401620012e494939291906200a6dd565b604080516020601f84018190048102820181019092528281526000916200700f918585808385018382808284376000920191909152509293925050620096769050565b9050670de0b6b3a76400008110806200702a5750603c548110155b15620070535784848484604051630a5a604160e01b8152600401620012e494939291906200a6dd565b603b5562007768565b620070ca6040518060400160405280601181526020017019995b1bdb9e54db185cda105b5bdd5b9d607a1b81525085858080601f0160208091040260200160405190810160405280939291908181526020018383808284376000920191909152509293925050620096199050565b156200718c5760208114620070fc5783838383604051630a5a604160e01b8152600401620012e494939291906200a6dd565b604080516020601f84018190048102820181019092528281526000916200713f918585808385018382808284376000920191909152509293925050620096769050565b9050678ac7230489e800008110806200715a5750603b548111155b15620071835784848484604051630a5a604160e01b8152600401620012e494939291906200a6dd565b603c5562007768565b620071f96040518060400160405280601081526020016f646f776e74696d654a61696c54696d6560801b81525085858080601f0160208091040260200160405190810160405280939291908181526020018383808284376000920191909152509293925050620096199050565b15620072b657602081146200722b5783838383604051630a5a604160e01b8152600401620012e494939291906200a6dd565b604080516020601f84018190048102820181019092528281526000916200726e918585808385018382808284376000920191909152509293925050620096769050565b905062015180811080620072845750603e548110155b15620072ad5784848484604051630a5a604160e01b8152600401620012e494939291906200a6dd565b603d5562007768565b620073216040518060400160405280600e81526020016d66656c6f6e794a61696c54696d6560901b81525085858080601f0160208091040260200160405190810160405280939291908181526020018383808284376000920191909152509293925050620096199050565b15620073de5760208114620073535783838383604051630a5a604160e01b8152600401620012e494939291906200a6dd565b604080516020601f840181900481028201810190925282815260009162007396918585808385018382808284376000920191909152509293925050620096769050565b90506203f480811080620073ac5750603d548111155b15620073d55784848484604051630a5a604160e01b8152600401620012e494939291906200a6dd565b603e5562007768565b620074586040518060400160405280601c81526020017f6d617846656c6f6e794265747765656e42726561746865426c6f636b0000000081525085858080601f0160208091040260200160405190810160405280939291908181526020018383808284376000920191909152509293925050620096199050565b156200750457602081146200748a5783838383604051630a5a604160e01b8152600401620012e494939291906200a6dd565b604080516020601f8401819004810282018101909252828152600091620074cd918585808385018382808284376000920191909152509293925050620096769050565b905080600003620074fb5784848484604051630a5a604160e01b8152600401620012e494939291906200a6dd565b604a5562007768565b620075726040518060400160405280601181526020017039ba30b5b2a43ab1283937ba32b1ba37b960791b81525085858080601f0160208091040260200160405190810160405280939291908181526020018383808284376000920191909152509293925050620096199050565b15620076325760148114620075a45783838383604051630a5a604160e01b8152600401620012e494939291906200a6dd565b6000620075ec601484848080601f0160208091040260200160405190810160405280939291908181526020018383808284376000920191909152509293925050620096769050565b90506001600160a01b038116620076205784848484604051630a5a604160e01b8152600401620012e494939291906200a6dd565b6200762b816200967b565b5062007768565b620076996040518060400160405280600a8152602001696d61784e6f646549447360b01b81525085858080601f0160208091040260200160405190810160405280939291908181526020018383808284376000920191909152509293925050620096199050565b15620077455760208114620076cb5783838383604051630a5a604160e01b8152600401620012e494939291906200a6dd565b604080516020601f84018190048102820181019092528281526000916200770e918585808385018382808284376000920191909152509293925050620096769050565b9050806000036200773c5784848484604051630a5a604160e01b8152600401620012e494939291906200a6dd565b604e5562007768565b838383836040516325ee20d560e21b8152600401620012e494939291906200a6dd565b7ff1ce9b2cbf50eeb05769a29e2543fd350cab46894a7dd9978a12d534bb20e633848484846040516200779f94939291906200a6dd565b60405180910390a150505050565b60005462010000900460ff1615620077d857604051631785c68160e01b815260040160405180910390fd5b3360009081526001602052604090205460ff16156200780a5760405163b1d02c3d60e01b815260040160405180910390fd5b816000816001600160401b038111156200782857620078286200993b565b60405190808252806020026020018201604052801562007852578160200160208202803683370190505b5090506000805b8381101562007950576200789b8787838181106200787b576200787b6200a266565b9050602002016020810190620078929190620097cc565b603f9062008cf9565b620078b95760405163056e881160e01b815260040160405180910390fd5b60416000888884818110620078d257620078d26200a266565b9050602002016020810190620078e99190620097cc565b6001600160a01b03908116825260208201929092526040016000206002015484519116925082908490839081106200792557620079256200a266565b6001600160a01b039092166020928302919091019091015262007948816200a27c565b905062007859565b50604051634484077560e01b8152612005906344840775906200337d90859088906004016200a2c8565b60608060006200798b603f62009071565b90508085101562007b4f578315620079a45783620079a6565b805b9350600084620079b787846200a298565b11620079cf57620079c986836200a298565b620079d1565b845b9050806001600160401b03811115620079ee57620079ee6200993b565b60405190808252806020026020018201604052801562007a18578160200160208202803683370190505b509350806001600160401b0381111562007a365762007a366200993b565b60405190808252806020026020018201604052801562007a60578160200160208202803683370190505b50925060005b8181101562007b4c5762007a7f6200453882896200a1fb565b85828151811062007a945762007a946200a266565b60200260200101906001600160a01b031690816001600160a01b0316815250506041600086838151811062007acd5762007acd6200a266565b60200260200101516001600160a01b03166001600160a01b0316815260200190815260200160002060020160009054906101000a90046001600160a01b031684828151811062007b215762007b216200a266565b6001600160a01b039092166020928302919091019091015262007b44816200a27c565b905062007a66565b50505b9250925092565b60008162007b66603f8262008cf9565b62007b845760405163056e881160e01b815260040160405180910390fd5b50506001600160a01b03166000908152604160205260409020600c015490565b336110011462007bcc57604051630f22c43960e41b81526110016004820152602401620012e4565b60005462010000900460ff161562007bf757604051631785c68160e01b815260040160405180910390fd5b6001600160a01b038082166000908152604360205260409020541662007c1f603f8262008cf9565b62007c3d5760405163056e881160e01b815260040160405180910390fd5b6001600160a01b03811660009081526041602052604081209062007c6562015180426200a1d8565b604a546000828152604b60205260409020549192501162007c995760405163bd52fcdb60e01b815260040160405180910390fd5b6000818152604b6020526040812080546001929062007cba9084906200a1fb565b90915550506001600160a01b0384166000908152604460205260409020541580159062007d0f57506001600160a01b038416600090815260446020526040902054429062007d0d9062015180906200a1fb565b105b1562007d2e576040516330abb81d60e21b815260040160405180910390fd5b60008062007d3e85600062008d1c565b915091508162007d6157604051631b919bb160e11b815260040160405180910390fd5b6002840154603c5460405163045bc4d160e41b815260048101919091526000916001600160a01b0316906345bc4d10906024016020604051808303816000875af115801562007db4573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019062007dda91906200a211565b905062007de8858362008da4565b84546040516335409f7f60e01b81526001600160a01b039091166004820152611000906335409f7f90602401600060405180830381600087803b15801562007e2f57600080fd5b505af115801562007e44573d6000803e3d6000fd5b50505050856001600160a01b03167f6e9a2ee7aee95665e3a774a212eb11441b217e3e4656ab9563793094689aabb28383600060405162007e88939291906200a22b565b60405180910390a26002850154604051633041949b60e01b815261200591633041949b916200615e916001600160a01b0316908a906004016200a198565b6001600160a01b038082166000908152604160209081526040808320815161018081018352815486168152600182015486169381019390935260028101549094169082015260038301546060820152600483018054929384938493849390929160808401919062007f37906200a162565b80601f016020809104026020016040519081016040528092919081815260200182805462007f65906200a162565b801562007fb65780601f1062007f8a5761010080835404028352916020019162007fb6565b820191906000526020600020905b81548152906001019060200180831162007f9857829003601f168201915b505050505081526020016005820160405180608001604052908160008201805462007fe1906200a162565b80601f01602080910402602001604051908101604052809291908181526020018280546200800f906200a162565b8015620080605780601f10620080345761010080835404028352916020019162008060565b820191906000526020600020905b8154815290600101906020018083116200804257829003601f168201915b505050505081526020016001820180546200807b906200a162565b80601f0160208091040260200160405190810160405280929190818152602001828054620080a9906200a162565b8015620080fa5780601f10620080ce57610100808354040283529160200191620080fa565b820191906000526020600020905b815481529060010190602001808311620080dc57829003601f168201915b5050505050815260200160028201805462008115906200a162565b80601f016020809104026020016040519081016040528092919081815260200182805462008143906200a162565b8015620081945780601f10620081685761010080835404028352916020019162008194565b820191906000526020600020905b8154815290600101906020018083116200817657829003601f168201915b50505050508152602001600382018054620081af906200a162565b80601f0160208091040260200160405190810160405280929190818152602001828054620081dd906200a162565b80156200822e5780601f1062008202576101008083540402835291602001916200822e565b820191906000526020600020905b8154815290600101906020018083116200821057829003601f168201915b505050919092525050508152604080516060808201835260098501546001600160401b038082168452600160401b82048116602080860191909152600160801b9092041683850152840191909152600a84015460ff16151582840152600b84015490830152600c8301546080830152600d8301546001600160a01b031660a0830152805161026081019182905260c09092019190600e84019060139082845b815481526020019060010190808311620082cd5750505091909252505050606081015160e0820151610100909201519097919650945092505050565b60005462010000900460ff16156200833457604051631785c68160e01b815260040160405180910390fd5b3360009081526001602052604090205460ff1615620083665760405163b1d02c3d60e01b815260040160405180910390fd5b6200837062008f12565b6200837d603f8262008cf9565b6200839b5760405163056e881160e01b815260040160405180910390fd5b6000620083a762008f12565b6001600160a01b0381166000908152604160205260409020600c810154919250904290620083da9062015180906200a1fb565b1115620083fa57604051631f92cdbd60e11b815260040160405180910390fd5b6005810180546200840b906200a162565b80601f016020809104026020016040519081016040528092919081815260200182805462008439906200a162565b80156200848a5780601f106200845e576101008083540402835291602001916200848a565b820191906000526020600020905b8154815290600101906020018083116200846c57829003601f168201915b5050508287525085916005840191508190620084a790826200a713565b5060208201516001820190620084be90826200a713565b5060408201516002820190620084d590826200a713565b5060608201516003820190620084ec90826200a713565b505042600c830155506040516001600160a01b038316907f85d6366b336ade7f106987ec7a8eac1e8799e508aeab045a39d2f63e0dc969d990600090a250505050565b60005462010000900460ff16156200855a57604051631785c68160e01b815260040160405180910390fd5b3360009081526001602052604090205460ff16156200858c5760405163b1d02c3d60e01b815260040160405180910390fd5b828114620085ad576040516341abc80160e01b815260040160405180910390fd5b60005b838110156200861e576200860b858583818110620085d257620085d26200a266565b9050602002016020810190620085e99190620097cc565b848484818110620085fe57620085fe6200a266565b905060200201356200950d565b62008616816200a27c565b9050620085b0565b5050505050565b6001600160a01b038082166000908152604160209081526040808320815161018081018352815486168152600182015486169381019390935260028101549094169082015260038301546060820152600483018054929384939091608084019162008690906200a162565b80601f0160208091040260200160405190810160405280929190818152602001828054620086be906200a162565b80156200870f5780601f10620086e3576101008083540402835291602001916200870f565b820191906000526020600020905b815481529060010190602001808311620086f157829003601f168201915b50505050508152602001600582016040518060800160405290816000820180546200873a906200a162565b80601f016020809104026020016040519081016040528092919081815260200182805462008768906200a162565b8015620087b95780601f106200878d57610100808354040283529160200191620087b9565b820191906000526020600020905b8154815290600101906020018083116200879b57829003601f168201915b50505050508152602001600182018054620087d4906200a162565b80601f016020809104026020016040519081016040528092919081815260200182805462008802906200a162565b8015620088535780601f10620088275761010080835404028352916020019162008853565b820191906000526020600020905b8154815290600101906020018083116200883557829003601f168201915b505050505081526020016002820180546200886e906200a162565b80601f01602080910402602001604051908101604052809291908181526020018280546200889c906200a162565b8015620088ed5780601f10620088c157610100808354040283529160200191620088ed565b820191906000526020600020905b815481529060010190602001808311620088cf57829003601f168201915b5050505050815260200160038201805462008908906200a162565b80601f016020809104026020016040519081016040528092919081815260200182805462008936906200a162565b8015620089875780601f106200895b5761010080835404028352916020019162008987565b820191906000526020600020905b8154815290600101906020018083116200896957829003601f168201915b505050919092525050508152604080516060808201835260098501546001600160401b038082168452600160401b82048116602080860191909152600160801b9092041683850152840191909152600a84015460ff16151582840152600b84015490830152600c8301546080830152600d8301546001600160a01b031660a0830152805161026081019182905260c09092019190600e84019060139082845b81548152602001906001019080831162008a265750505091909252505050604001519392505050565b600062008a5e603f8462008cf9565b62008a7c5760405163056e881160e01b815260040160405180910390fd5b6001600160a01b038381166000908152604160205260409081902060020154905163aa1966cd60e01b81526004810185905291169063aa1966cd9060240162005aa0565b60005462010000900460ff161562008aeb57604051631785c68160e01b815260040160405180910390fd5b3360009081526001602052604090205460ff161562008b1d5760405163b1d02c3d60e01b815260040160405180910390fd5b62008b2762008f12565b62008b34603f8262008cf9565b62008b525760405163056e881160e01b815260040160405180910390fd5b600062008b5e62008f12565b905062008b6f81878787876200922c565b62008b8d57604051631647e3cb60e11b815260040160405180910390fd5b60006001600160a01b03166045878760405162008bac9291906200a1b2565b908152604051908190036020019020546001600160a01b03161462008be4576040516311fdb94760e01b815260040160405180910390fd5b6001600160a01b0381166000908152604160205260409020600c810154429062008c139062015180906200a1fb565b111562008c3357604051631f92cdbd60e11b815260040160405180910390fd5b4260468260040160405162008c4991906200a7db565b908152604051908190036020019020556004810162008c6a8789836200a3c6565b5042600c820155604051829060459062008c88908a908a906200a1b2565b90815260405190819003602001812080546001600160a01b039384166001600160a01b0319909116179055908316907f783156582145bd0ff7924fae6953ba054cf1233eb60739a200ddb10de068ff0d9062008ce8908a908a906200a697565b60405180910390a250505050505050565b6001600160a01b0381166000908152600183016020526040812054151562005ae4565b6000806000848460405160200162008d369291906200a859565b60408051601f1981840301815291815281516020928301206000818152604c9093529120549091504281111562008d7657600080935093505050620026aa565b603e5462008d8590426200a1fb565b6000928352604c60205260409092208290555060019590945092505050565b6000600162008db4603f62009071565b62008dc091906200a298565b604954108015915062008e0c5760018301546040516001600160a01b03909116907f2afdc18061ac21cff7d9f11527ab9c8dec6fabd4edf6f894ed634bebd6a20d4590600090a2505050565b82600b015482111562008e2157600b83018290555b600a83015460ff166200649c57600a8301805460ff191660019081179091556049805460009062008e549084906200a1fb565b909155505060018301546040516001600160a01b03909116907f4905ac32602da3fb8b4b7b00c285e5fc4c6c2308cc908b4a1e4e9625a29c90a390600090a2505050565b336000908152604360205260408120546001600160a01b03161580159062008ecd575033600090815260446020526040902054155b1562008ef05750336000908152604360205260409020546001600160a01b031690565b62008efa62008f12565b905090565b604e5460000362008f10576005604e555b565b336000908152604d60205260408120546001600160a01b03161562008f4e5750336000908152604d60205260409020546001600160a01b031690565b503390565b6001600160a01b0381166000908152604160205260409020600a81015460ff161562008f7d575050565b6036546002820154604051630913db4760e01b81526001600160a01b03858116600483015290911690630913db4790602401602060405180830381865afa15801562008fcd573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019062008ff391906200a211565b1015620067f7576200901581603d54426200900f91906200a1fb565b62008da4565b80546040516335409f7f60e01b81526001600160a01b039091166004820152611000906335409f7f90602401600060405180830381600087803b1580156200905c57600080fd5b505af115801562006308573d6000803e3d6000fd5b600062005ae7825490565b600062005ae48383620096e7565b600080829050600381511080620090a2575060098151115b15620090b15750600092915050565b604181600081518110620090c957620090c96200a266565b016020015160f81c1080620090fb5750605a81600081518110620090f157620090f16200a266565b016020015160f81c115b156200910a5750600092915050565b60015b8151811015620092225760308282815181106200912e576200912e6200a266565b016020015160f81c10806200915f575060398282815181106200915557620091556200a266565b016020015160f81c115b8015620091af575060418282815181106200917e576200917e6200a266565b016020015160f81c1080620091af5750605a828281518110620091a557620091a56200a266565b016020015160f81c115b8015620091ff57506061828281518110620091ce57620091ce6200a266565b016020015160f81c1080620091ff5750607a828281518110620091f557620091f56200a266565b016020015160f81c115b156200920f575060009392505050565b6200921a816200a27c565b90506200910d565b5060019392505050565b600060308414158062009240575060608214155b156200924f5750600062009353565b6000868686466040516020016200926a94939291906200a8a3565b60408051808303601f1901815282825280516020918201208184528383019092529092506000919060208201818036833701905050905081602082015260008186868a8a604051602001620092c49594939291906200a8d0565b60408051808303601f190181526001808452838301909252925060009190602082018180368337019050509050815160016020830182602086016066600019fa6200930e57600080fd5b506000816000815181106200932757620093276200a266565b016020015160f81c905060018114620093495760009550505050505062009353565b6001955050505050505b95945050505050565b60008061200361dead604051620093739062009786565b6001600160a01b03928316815291166020820152606060408201819052600090820152608001604051809103906000f080158015620093b6573d6000803e3d6000fd5b509050806001600160a01b031663f399e22e3486866040518463ffffffff1660e01b8152600401620093ea9291906200a908565b6000604051808303818588803b1580156200940457600080fd5b505af115801562009419573d6000803e3d6000fd5b50506040516001600160a01b038086169450881692507fd481492e4e93bb36b4c12a5af93f03be3bf04b454dfbc35dd2663fa26f44d5b09150600090a39392505050565b600062005ae4836001600160a01b03841662009714565b600054610100900460ff16620094e15760405162461bcd60e51b815260206004820152602b60248201527f496e697469616c697a61626c653a20636f6e7472616374206973206e6f74206960448201526a6e697469616c697a696e6760a81b6064820152608401620012e4565b600080546001600160a01b039092166301000000026301000000600160b81b0319909216919091179055565b816200951b603f8262008cf9565b620095395760405163056e881160e01b815260040160405180910390fd5b6001600160a01b03838116600090815260416020526040808220600201549051635569f64b60e11b8152336004820152602481018690529192169063aad3ec96906044016020604051808303816000875af11580156200959d573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190620095c391906200a211565b9050336001600160a01b0316846001600160a01b03167ff7a40077ff7a04c7e61f6f26fb13774259ddf1b6bce9ecf26a8276cdd3992683836040516200960b91815260200190565b60405180910390a350505050565b6000816040516020016200962e91906200a92e565b60405160208183030381529060405280519060200120836040516020016200965791906200a92e565b6040516020818303038152906040528051906020012014905092915050565b015190565b600080546040516001600160a01b0380851693630100000090930416917f44fc1b38a4abaa91ebd1b628a5b259a698f86238c8217d68f516e87769c60c0b91a3600080546001600160a01b039092166301000000026301000000600160b81b0319909216919091179055565b60008260000182815481106200970157620097016200a266565b9060005260206000200154905092915050565b60008181526001830160205260408120546200975d5750815460018181018455600084815260208082209093018490558454848252828601909352604090209190915562005ae7565b50600062005ae7565b50805460008255906000526020600020908101906200190f919062009794565b610e96806200a94d83390190565b5b80821115620097ab576000815560010162009795565b5090565b80356001600160a01b0381168114620097c757600080fd5b919050565b600060208284031215620097df57600080fd5b62005ae482620097af565b60008083601f840112620097fd57600080fd5b5081356001600160401b038111156200981557600080fd5b602083019150836020828501011115620026aa57600080fd5b600080602083850312156200984257600080fd5b82356001600160401b038111156200985957600080fd5b6200986785828601620097ea565b90969095509350505050565b6000806000604084860312156200988957600080fd5b833560ff811681146200989b57600080fd5b925060208401356001600160401b03811115620098b757600080fd5b620098c586828701620097ea565b9497909650939450505050565b60005b83811015620098ef578181015183820152602001620098d5565b50506000910152565b6000815180845262009912816020860160208601620098d2565b601f01601f19169290920160200192915050565b60208152600062005ae46020830184620098f8565b634e487b7160e01b600052604160045260246000fd5b604051608081016001600160401b03811182821017156200997657620099766200993b565b60405290565b60006001600160401b03808411156200999957620099996200993b565b604051601f8501601f19908116603f01168101908282118183101715620099c457620099c46200993b565b81604052809350858152868686011115620099de57600080fd5b858560208301376000602087830101525050509392505050565b60006020828403121562009a0b57600080fd5b81356001600160401b0381111562009a2257600080fd5b8201601f8101841362009a3457600080fd5b62009a45848235602084016200997c565b949350505050565b60008083601f84011262009a6057600080fd5b5081356001600160401b0381111562009a7857600080fd5b6020830191508360208260051b8501011115620026aa57600080fd5b6000806020838503121562009aa857600080fd5b82356001600160401b0381111562009abf57600080fd5b620098678582860162009a4d565b600081518084526020808501945080840160005b8381101562009b085781516001600160a01b03168752958201959082019060010162009ae1565b509495945050505050565b60408152600062009b28604083018562009acd565b6020838203818501528185518084528284019150828160051b8501018388016000805b8481101562009ba257878403601f19018652825180518086529088019088860190845b8181101562009b8c5783518352928a0192918a019160010162009b6e565b5050968801969450509186019160010162009b4b565b50919a9950505050505050505050565b6000806040838503121562009bc657600080fd5b62009bd183620097af565b946020939093013593505050565b80358015158114620097c757600080fd5b6000806000806080858703121562009c0757600080fd5b62009c1285620097af565b935062009c2260208601620097af565b92506040850135915062009c396060860162009bdf565b905092959194509250565b6001600160401b03811681146200190f57600080fd5b60006020828403121562009c6d57600080fd5b813562009c7a8162009c44565b9392505050565b6000806040838503121562009c9557600080fd5b50508035926020909101359150565b60808152600062009cb9608083018762009acd565b82810360208481019190915286518083528782019282019060005b8181101562009cf25784518352938301939183019160010162009cd4565b5050848103604086015286518082528282019350600581901b8201830183890160005b8381101562009d4757601f1985840301875262009d34838351620098f8565b9686019692509085019060010162009d15565b5050809550505050505082606083015295945050505050565b600080600080600080600087890360e081121562009d7d57600080fd5b62009d8889620097af565b975060208901356001600160401b038082111562009da557600080fd5b62009db38c838d01620097ea565b909950975060408b013591508082111562009dcd57600080fd5b62009ddb8c838d01620097ea565b90975095508591506060605f198401121562009df657600080fd5b60608b01945060c08b013592508083111562009e1157600080fd5b505088016080818b03121562009e2657600080fd5b8091505092959891949750929550565b6000806040838503121562009e4a57600080fd5b62009e5583620097af565b915062009e656020840162009bdf565b90509250929050565b60208152600082516080602084015262009e8c60a0840182620098f8565b90506020840151601f198085840301604086015262009eac8383620098f8565b9250604086015191508085840301606086015262009ecb8383620098f8565b9250606086015191508085840301608086015250620093538282620098f8565b6000806000806040858703121562009f0257600080fd5b84356001600160401b038082111562009f1a57600080fd5b62009f2888838901620097ea565b9096509450602087013591508082111562009f4257600080fd5b5062009f5187828801620097ea565b95989497509550505050565b60008060006040848603121562009f7357600080fd5b83356001600160401b0381111562009f8a57600080fd5b62009f988682870162009a4d565b909450925062009fad905060208501620097af565b90509250925092565b60608152600062009fcb606083018662009acd565b828103602084015262009fdf818662009acd565b915050826040830152949350505050565b600082601f8301126200a00257600080fd5b62005ae4838335602085016200997c565b6000602082840312156200a02657600080fd5b81356001600160401b03808211156200a03e57600080fd5b90830190608082860312156200a05357600080fd5b6200a05d62009951565b8235828111156200a06d57600080fd5b6200a07b8782860162009ff0565b8252506020830135828111156200a09157600080fd5b6200a09f8782860162009ff0565b6020830152506040830135828111156200a0b857600080fd5b6200a0c68782860162009ff0565b6040830152506060830135828111156200a0df57600080fd5b6200a0ed8782860162009ff0565b60608301525095945050505050565b600080600080604085870312156200a11357600080fd5b84356001600160401b03808211156200a12b57600080fd5b6200a1398883890162009a4d565b909650945060208701359150808211156200a15357600080fd5b5062009f518782880162009a4d565b600181811c908216806200a17757607f821691505b602082108103620020dc57634e487b7160e01b600052602260045260246000fd5b6001600160a01b0392831681529116602082015260400190565b8183823760009101908152919050565b634e487b7160e01b600052601160045260246000fd5b6000826200a1f657634e487b7160e01b600052601260045260246000fd5b500490565b8082018082111562005ae75762005ae76200a1c2565b6000602082840312156200a22457600080fd5b5051919050565b8381526020810183905260608101600383106200a25857634e487b7160e01b600052602160045260246000fd5b826040830152949350505050565b634e487b7160e01b600052603260045260246000fd5b6000600182016200a291576200a2916200a1c2565b5060010190565b8181038181111562005ae75762005ae76200a1c2565b808202811582820484141762005ae75762005ae76200a1c2565b6040815260006200a2dd604083018562009acd565b905060018060a01b03831660208301529392505050565b6001600160401b038281168282160390808211156200a317576200a3176200a1c2565b5092915050565b6000808335601e198436030181126200a33657600080fd5b8301803591506001600160401b038211156200a35157600080fd5b602001915036819003821315620026aa57600080fd5b601f8211156200649c57600081815260208120601f850160051c810160208610156200a3905750805b601f850160051c820191505b8181101562006308578281556001016200a39c565b600019600383901b1c191660019190911b1790565b6001600160401b038311156200a3e0576200a3e06200993b565b6200a3f8836200a3f183546200a162565b836200a367565b6000601f8411600181146200a42b57600085156200a4165750838201355b6200a42286826200a3b1565b8455506200861e565b600083815260209020601f19861690835b828110156200a45e57868501358255602094850194600190920191016200a43c565b50868210156200a47c5760001960f88860031b161c19848701351681555b505060018560011b0183555050505050565b6200a49a82836200a31e565b6001600160401b038111156200a4b4576200a4b46200993b565b6200a4cc816200a4c585546200a162565b856200a367565b6000601f8211600181146200a4ff57600083156200a4ea5750838201355b6200a4f684826200a3b1565b8655506200a55c565b600085815260209020601f19841690835b828110156200a53257868501358255602094850194600190920191016200a510565b50848210156200a5505760001960f88660031b161c19848701351681555b505060018360011b0185555b505050506200a56f60208301836200a31e565b6200a57f8183600186016200a3c6565b50506200a59060408301836200a31e565b6200a5a08183600286016200a3c6565b50506200a5b160608301836200a31e565b6200a5c18183600386016200a3c6565b50505050565b81356200a5d48162009c44565b6001600160401b03811690508154816001600160401b0319821617835560208401356200a6018162009c44565b6fffffffffffffffff0000000000000000604091821b166fffffffffffffffffffffffffffffffff198316841781178555908501356200a6418162009c44565b6001600160c01b0319929092169092179190911760809190911b67ffffffffffffffff60801b1617905550565b81835281816020850137506000828201602090810191909152601f909101601f19169091010190565b60208152600062009a456020830184866200a66e565b634e487b7160e01b600052603160045260246000fd5b6000816200a6d5576200a6d56200a1c2565b506000190190565b6040815260006200a6f36040830186886200a66e565b82810360208401526200a7088185876200a66e565b979650505050505050565b81516001600160401b038111156200a72f576200a72f6200993b565b6200a747816200a74084546200a162565b846200a367565b602080601f8311600181146200a77b57600084156200a7665750858301515b6200a77285826200a3b1565b86555062006308565b600085815260208120601f198616915b828110156200a7ac578886015182559484019460019091019084016200a78b565b50858210156200a7cb5787850151600019600388901b60f8161c191681555b5050505050600190811b01905550565b60008083546200a7eb816200a162565b600182811680156200a80657600181146200a81c576200a84d565b60ff19841687528215158302870194506200a84d565b8760005260208060002060005b858110156200a8445781548a8201529084019082016200a829565b50505082870194505b50929695505050505050565b6bffffffffffffffffffffffff198360601b1681526000600383106200a88f57634e487b7160e01b600052602160045260246000fd5b5060f89190911b6014820152601501919050565b6bffffffffffffffffffffffff198560601b16815282846014830137601492019182015260340192915050565b600086516200a8e4818460208b01620098d2565b82018587823760009086019081528385823760009301928352509095945050505050565b6001600160a01b038316815260406020820181905260009062009a4590830184620098f8565b600082516200a942818460208701620098d2565b919091019291505056fe608060405260405162000e9638038062000e96833981016040819052620000269162000497565b828162000036828260006200004d565b50620000449050826200008a565b505050620005ca565b6200005883620000e5565b600082511180620000665750805b1562000085576200008383836200012760201b620001691760201c565b505b505050565b7f7e644d79422f17c01e4894b5f4f588d331ebfa28653d42ae832dc59e38c9798f620000b562000156565b604080516001600160a01b03928316815291841660208301520160405180910390a1620000e2816200018f565b50565b620000f08162000244565b6040516001600160a01b038216907fbc7cd75a20ee27fd9adebab32041f755214dbc6bffa90cc0225b39da2e5c2d3b90600090a250565b60606200014f838360405180606001604052806027815260200162000e6f60279139620002f8565b9392505050565b60006200018060008051602062000e4f83398151915260001b6200037760201b620001951760201c565b546001600160a01b0316919050565b6001600160a01b038116620001fa5760405162461bcd60e51b815260206004820152602660248201527f455243313936373a206e65772061646d696e20697320746865207a65726f206160448201526564647265737360d01b60648201526084015b60405180910390fd5b806200022360008051602062000e4f83398151915260001b6200037760201b620001951760201c565b80546001600160a01b0319166001600160a01b039290921691909117905550565b6200025a816200037a60201b620001981760201c565b620002be5760405162461bcd60e51b815260206004820152602d60248201527f455243313936373a206e657720696d706c656d656e746174696f6e206973206e60448201526c1bdd08184818dbdb9d1c9858dd609a1b6064820152608401620001f1565b80620002237f360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc60001b6200037760201b620001951760201c565b6060600080856001600160a01b03168560405162000317919062000577565b600060405180830381855af49150503d806000811462000354576040519150601f19603f3d011682016040523d82523d6000602084013e62000359565b606091505b5090925090506200036d8683838762000389565b9695505050505050565b90565b6001600160a01b03163b151590565b60608315620003fd578251600003620003f5576001600160a01b0385163b620003f55760405162461bcd60e51b815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e74726163740000006044820152606401620001f1565b508162000409565b62000409838362000411565b949350505050565b815115620004225781518083602001fd5b8060405162461bcd60e51b8152600401620001f1919062000595565b80516001600160a01b03811681146200045657600080fd5b919050565b634e487b7160e01b600052604160045260246000fd5b60005b838110156200048e57818101518382015260200162000474565b50506000910152565b600080600060608486031215620004ad57600080fd5b620004b8846200043e565b9250620004c8602085016200043e565b60408501519092506001600160401b0380821115620004e657600080fd5b818601915086601f830112620004fb57600080fd5b8151818111156200051057620005106200045b565b604051601f8201601f19908116603f011681019083821181831017156200053b576200053b6200045b565b816040528281528960208487010111156200055557600080fd5b6200056883602083016020880162000471565b80955050505050509250925092565b600082516200058b81846020870162000471565b9190910192915050565b6020815260008251806020840152620005b681604085016020870162000471565b601f01601f19169190910160400192915050565b61087580620005da6000396000f3fe60806040523661001357610011610017565b005b6100115b61001f6101a7565b6001600160a01b0316330361015f5760606001600160e01b0319600035166364d3180d60e11b810161005a576100536101da565b9150610157565b63587086bd60e11b6001600160e01b031982160161007a57610053610231565b63070d7c6960e41b6001600160e01b031982160161009a57610053610277565b621eb96f60e61b6001600160e01b03198216016100b9576100536102a8565b63a39f25e560e01b6001600160e01b03198216016100d9576100536102e8565b60405162461bcd60e51b815260206004820152604260248201527f5472616e73706172656e745570677261646561626c6550726f78793a2061646d60448201527f696e2063616e6e6f742066616c6c6261636b20746f2070726f78792074617267606482015261195d60f21b608482015260a4015b60405180910390fd5b815160208301f35b6101676102fc565b565b606061018e83836040518060600160405280602781526020016108426027913961030c565b9392505050565b90565b6001600160a01b03163b151590565b60007fb53127684a568b3173ae13b9f8a6016e243e63b6e8ee1178d6a717850b5d61035b546001600160a01b0316919050565b60606101e4610384565b60006101f33660048184610695565b81019061020091906106db565b905061021d8160405180602001604052806000815250600061038f565b505060408051602081019091526000815290565b60606000806102433660048184610695565b810190610250919061070c565b915091506102608282600161038f565b604051806020016040528060008152509250505090565b6060610281610384565b60006102903660048184610695565b81019061029d91906106db565b905061021d816103bb565b60606102b2610384565b60006102bc6101a7565b604080516001600160a01b03831660208201529192500160405160208183030381529060405291505090565b60606102f2610384565b60006102bc610412565b610167610307610412565b610421565b6060600080856001600160a01b03168560405161032991906107f2565b600060405180830381855af49150503d8060008114610364576040519150601f19603f3d011682016040523d82523d6000602084013e610369565b606091505b509150915061037a86838387610445565b9695505050505050565b341561016757600080fd5b610398836104c6565b6000825111806103a55750805b156103b6576103b48383610169565b505b505050565b7f7e644d79422f17c01e4894b5f4f588d331ebfa28653d42ae832dc59e38c9798f6103e46101a7565b604080516001600160a01b03928316815291841660208301520160405180910390a161040f81610506565b50565b600061041c6105af565b905090565b3660008037600080366000845af43d6000803e808015610440573d6000f35b3d6000fd5b606083156104b45782516000036104ad576001600160a01b0385163b6104ad5760405162461bcd60e51b815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e7472616374000000604482015260640161014e565b50816104be565b6104be83836105d7565b949350505050565b6104cf81610601565b6040516001600160a01b038216907fbc7cd75a20ee27fd9adebab32041f755214dbc6bffa90cc0225b39da2e5c2d3b90600090a250565b6001600160a01b03811661056b5760405162461bcd60e51b815260206004820152602660248201527f455243313936373a206e65772061646d696e20697320746865207a65726f206160448201526564647265737360d01b606482015260840161014e565b807fb53127684a568b3173ae13b9f8a6016e243e63b6e8ee1178d6a717850b5d61035b80546001600160a01b0319166001600160a01b039290921691909117905550565b60007f360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc6101cb565b8151156105e75781518083602001fd5b8060405162461bcd60e51b815260040161014e919061080e565b6001600160a01b0381163b61066e5760405162461bcd60e51b815260206004820152602d60248201527f455243313936373a206e657720696d706c656d656e746174696f6e206973206e60448201526c1bdd08184818dbdb9d1c9858dd609a1b606482015260840161014e565b807f360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc61058e565b600080858511156106a557600080fd5b838611156106b257600080fd5b5050820193919092039150565b80356001600160a01b03811681146106d657600080fd5b919050565b6000602082840312156106ed57600080fd5b61018e826106bf565b634e487b7160e01b600052604160045260246000fd5b6000806040838503121561071f57600080fd5b610728836106bf565b9150602083013567ffffffffffffffff8082111561074557600080fd5b818501915085601f83011261075957600080fd5b81358181111561076b5761076b6106f6565b604051601f8201601f19908116603f01168101908382118183101715610793576107936106f6565b816040528281528860208487010111156107ac57600080fd5b8260208601602083013760006020848301015280955050505050509250929050565b60005b838110156107e95781810151838201526020016107d1565b50506000910152565b600082516108048184602087016107ce565b9190910192915050565b602081526000825180602084015261082d8160408501602087016107ce565b601f01601f1916919091016040019291505056fe416464726573733a206c6f772d6c6576656c2064656c65676174652063616c6c206661696c6564a164736f6c6343000811000ab53127684a568b3173ae13b9f8a6016e243e63b6e8ee1178d6a717850b5d6103416464726573733a206c6f772d6c6576656c2064656c65676174652063616c6c206661696c6564a164736f6c6343000811000a \ No newline at end of file diff --git a/core/systemcontracts/pasteur/mainnet/GovernorContract b/core/systemcontracts/pasteur/mainnet/GovernorContract new file mode 100644 index 0000000000..4065cc7973 --- /dev/null +++ b/core/systemcontracts/pasteur/mainnet/GovernorContract @@ -0,0 +1 @@ +6080604052600436106103e85760003560e01c80637b3c71d311610208578063c28bc2fa11610118578063deaaa7cc116100ab578063ece40cc11161007a578063ece40cc114610e19578063f23a6e6114610e39578063f8ce560a14610e65578063fc0c546a14610e85578063fe0d94c114610ea657600080fd5b8063deaaa7cc14610cda578063e23a9a5214610d0e578063ea0217cf14610dd9578063eb9019d414610df957600080fd5b8063da95691a116100e7578063da95691a14610c2f578063dd42a1dd14610c4f578063dd4e2ba514610c74578063ddf0b00914610cba57600080fd5b8063c28bc2fa14610bbd578063c59057e414610bd0578063d07f91e914610bf0578063d33219b414610c1057600080fd5b8063a7713a701161019b578063b187bd261161016a578063b187bd2614610b23578063b58131b014610b41578063bc197c8114610b56578063c01f9e3714610b82578063c170ec0b14610ba257600080fd5b8063a7713a7014610aae578063a890c91014610ac3578063ab58fb8e14610ae3578063ac43175114610b0357600080fd5b806384b0196e116101d757806384b0196e14610a2657806391ddadf414610a4e57806397c3d33414610a7a5780639a802a6d14610a8e57600080fd5b80637b3c71d3146109bc5780637d5e81e2146109dc5780638129fc1c146109fc5780638456cb5914610a1157600080fd5b806332b8113e116103035780634838d1651161029657806354fd4d501161026557806354fd4d5014610912578063567813881461093c5780635f398a141461095c57806360c4247f1461097c57806370b0f6601461099c57600080fd5b80634838d1651461087c5780634a49ac4c146108ac5780634bf5d7e9146108cc578063533ddd14146108e157600080fd5b806340e58ee5116102d257806340e58ee5146107d1578063417c73a7146107f15780634385963214610811578063452115d61461085c57600080fd5b806332b8113e146107455780633932abb11461076e5780633bccf4fd146107845780633e4f49e6146107a457600080fd5b8063150b7a021161037b5780632656227d1161034a5780632656227d146106975780632d63f693146106aa5780632fe3e261146106e1578063328dd9821461071557600080fd5b8063150b7a02146105f0578063160cbed71461063457806317977c611461065457806324bc1a641461068257600080fd5b8063046f7da2116103b7578063046f7da21461054357806306f3f9e61461055857806306fdde0314610578578063143489d01461059a57600080fd5b8063013cf08b1461045857806301ffc9a7146104d357806302a251a314610503578063034201811461052357600080fd5b3661045357306103f6610eb9565b6001600160a01b0316146104515760405162461bcd60e51b815260206004820152601f60248201527f476f7665726e6f723a206d7573742073656e6420746f206578656375746f720060448201526064015b60405180910390fd5b005b600080fd5b34801561046457600080fd5b50610478610473366004615ca3565b610ed3565b604080519a8b526001600160a01b0390991660208b0152978901969096526060880194909452608087019290925260a086015260c085015260e084015215156101008301521515610120820152610140015b60405180910390f35b3480156104df57600080fd5b506104f36104ee366004615cbc565b610f8e565b60405190151581526020016104ca565b34801561050f57600080fd5b50610195545b6040519081526020016104ca565b34801561052f57600080fd5b5061051561053e366004615e02565b610f9f565b34801561054f57600080fd5b50610451611097565b34801561056457600080fd5b50610451610573366004615ca3565b611127565b34801561058457600080fd5b5061058d6111b2565b6040516104ca9190615ef8565b3480156105a657600080fd5b506105d86105b5366004615ca3565b60009081526101636020526040902054600160401b90046001600160a01b031690565b6040516001600160a01b0390911681526020016104ca565b3480156105fc57600080fd5b5061061b61060b366004615f20565b630a85bd0160e11b949350505050565b6040516001600160e01b031990911681526020016104ca565b34801561064057600080fd5b5061051561064f3660046160f7565b611245565b34801561066057600080fd5b5061051561066f366004616186565b6102c36020526000908152604090205481565b34801561068e57600080fd5b50610515611330565b6105156106a53660046160f7565b611356565b3480156106b657600080fd5b506105156106c5366004615ca3565b600090815261016360205260409020546001600160401b031690565b3480156106ed57600080fd5b506105157fb3b3f3b703cd84ce352197dcff232b1b5d3cfb2025ce47cf04742d0651f1af8881565b34801561072157600080fd5b50610735610730366004615ca3565b611449565b6040516104ca949392919061626c565b34801561075157600080fd5b5061028f546040516001600160401b0390911681526020016104ca565b34801561077a57600080fd5b5061019454610515565b34801561079057600080fd5b5061051561079f3660046162b9565b6116db565b3480156107b057600080fd5b506107c46107bf366004615ca3565b611751565b6040516104ca919061631d565b3480156107dd57600080fd5b506104516107ec366004615ca3565b61175c565b3480156107fd57600080fd5b5061045161080c366004616186565b611787565b34801561081d57600080fd5b506104f361082c366004616345565b60008281526101c6602090815260408083206001600160a01b038516845260080190915290205460ff1692915050565b34801561086857600080fd5b506105156108773660046160f7565b611808565b34801561088857600080fd5b506104f3610897366004616186565b60016020526000908152604090205460ff1681565b3480156108b857600080fd5b506104516108c7366004616186565b611816565b3480156108d857600080fd5b5061058d611891565b3480156108ed57600080fd5b506104f36108fc366004616186565b6102c16020526000908152604090205460ff1681565b34801561091e57600080fd5b506040805180820190915260018152603160f81b602082015261058d565b34801561094857600080fd5b50610515610957366004616375565b61193e565b34801561096857600080fd5b506105156109773660046163a1565b611967565b34801561098857600080fd5b50610515610997366004615ca3565b6119b1565b3480156109a857600080fd5b506104516109b7366004615ca3565b611a66565b3480156109c857600080fd5b506105156109d7366004616424565b611aee565b3480156109e857600080fd5b506105156109f736600461647d565b611b40565b348015610a0857600080fd5b50610451611c5b565b348015610a1d57600080fd5b50610451611e8d565b348015610a3257600080fd5b50610a3b611f23565b6040516104ca979695949392919061651d565b348015610a5a57600080fd5b50610a63611fc1565b60405165ffffffffffff90911681526020016104ca565b348015610a8657600080fd5b506064610515565b348015610a9a57600080fd5b50610515610aa936600461657f565b612035565b348015610aba57600080fd5b5061051561204c565b348015610acf57600080fd5b50610451610ade366004616186565b612079565b348015610aef57600080fd5b50610515610afe366004615ca3565b612101565b348015610b0f57600080fd5b50610451610b1e3660046165d7565b61219d565b348015610b2f57600080fd5b5060005462010000900460ff166104f3565b348015610b4d57600080fd5b506105156128e2565b348015610b6257600080fd5b5061061b610b71366004616636565b63bc197c8160e01b95945050505050565b348015610b8e57600080fd5b50610515610b9d366004615ca3565b6128ee565b348015610bae57600080fd5b506102c2546104f39060ff1681565b610451610bcb3660046166c9565b6128f9565b348015610bdc57600080fd5b50610515610beb3660046160f7565b612a09565b348015610bfc57600080fd5b50610451610c0b36600461670c565b612a43565b348015610c1c57600080fd5b5061022b546001600160a01b03166105d8565b348015610c3b57600080fd5b50610515610c4a366004616735565b612acb565b348015610c5b57600080fd5b50600054630100000090046001600160a01b03166105d8565b348015610c8057600080fd5b5060408051808201909152601a81527f737570706f72743d627261766f2671756f72756d3d627261766f000000000000602082015261058d565b348015610cc657600080fd5b50610451610cd5366004615ca3565b612b52565b348015610ce657600080fd5b506105157f150214d74d59b7d1e90c73fc22ef3d991dd0a76b046543d4d80ab92d2a50328f81565b348015610d1a57600080fd5b50610da9610d29366004616345565b60408051606081018252600080825260208201819052918101919091525060009182526101c6602090815260408084206001600160a01b0393909316845260089092018152918190208151606081018352905460ff8082161515835261010082041693820193909352620100009092046001600160601b03169082015290565b6040805182511515815260208084015160ff1690820152918101516001600160601b0316908201526060016104ca565b348015610de557600080fd5b50610451610df4366004615ca3565b612b75565b348015610e0557600080fd5b50610515610e143660046167d6565b612bfd565b348015610e2557600080fd5b50610451610e34366004615ca3565b612c1e565b348015610e4557600080fd5b5061061b610e54366004616802565b63f23a6e6160e01b95945050505050565b348015610e7157600080fd5b50610515610e80366004615ca3565b612ca6565b348015610e9157600080fd5b506101f8546105d8906001600160a01b031681565b610451610eb4366004615ca3565b612d35565b6000610ece61022b546001600160a01b031690565b905090565b8060008080808080808080610ee78a612101565b60008c815261016360205260409020549098506001600160401b03169650610f0e8b6128ee565b60008c81526101c66020526040812080546005820154600683015460078401546001600160a01b039093169e50949a509850929650919450610f4f8d611751565b90506002816007811115610f6557610f65616307565b1493506007816007811115610f7c57610f7c616307565b14925050509193959799509193959799565b6000610f9982612d58565b92915050565b60008061104361103b7fb3b3f3b703cd84ce352197dcff232b1b5d3cfb2025ce47cf04742d0651f1af888c8c8c8c604051610fdb92919061686a565b60405180910390208b80519060200120604051602001611020959493929190948552602085019390935260ff9190911660408401526060830152608082015260a00190565b60405160208183030381529060405280519060200120612d7d565b868686612daa565b90506110898a828b8b8b8080601f0160208091040260200160405190810160405280939291908181526020018383808284376000920191909152508d9250612dc8915050565b9a9950505050505050505050565b600054630100000090046001600160a01b031633146110c9576040516306fbb1e360e01b815260040160405180910390fd5b60005462010000900460ff166110f257604051636cd6020160e01b815260040160405180910390fd5b6000805462ff0000191681556040517f62451d457bc659158be6e6247f56ec1df424a5c7597f71c20c2bc44e0965c8f99190a1565b61112f610eb9565b6001600160a01b0316336001600160a01b03161461115f5760405162461bcd60e51b81526004016104489061687a565b30611168610eb9565b6001600160a01b0316146111a6576000803660405161118892919061686a565b604051809103902090505b8061119f610164612e6b565b0361119357505b6111af81612eea565b50565b606061016280546111c2906168b1565b80601f01602080910402602001604051908101604052809291908181526020018280546111ee906168b1565b801561123b5780601f106112105761010080835404028352916020019161123b565b820191906000526020600020905b81548152906001019060200180831161121e57829003601f168201915b5050505050905090565b6000805462010000900460ff161561127057604051631785c68160e01b815260040160405180910390fd5b3360009081526001602052604090205460ff16156112a15760405163b1d02c3d60e01b815260040160405180910390fd5b60005b855181101561131a576102c160008783815181106112c4576112c46168eb565b6020908102919091018101516001600160a01b031682528101919091526040016000205460ff1661130857604051630b094f2760e31b815260040160405180910390fd5b8061131281616917565b9150506112a4565b506113278585858561305b565b95945050505050565b6000610ece600161133f611fc1565b6113499190616930565b65ffffffffffff16612ca6565b60008061136586868686612a09565b9050600061137282611751565b9050600481600781111561138857611388616307565b14806113a5575060058160078111156113a3576113a3616307565b145b6113c15760405162461bcd60e51b815260040161044890616956565b6000828152610163602052604090819020600201805460ff19166001179055517f712ae1383f79ac853f8d882153778e0260ef8f03b504e2866e0593e04d2b291f906114109084815260200190565b60405180910390a16114258288888888613260565b6114328288888888613301565b61143f82888888886133e3565b5095945050505050565b60608060608060006101c66000878152602001908152602001600020905080600101816002018260030183600401838054806020026020016040519081016040528092919081815260200182805480156114cc57602002820191906000526020600020905b81546001600160a01b031681526001909101906020018083116114ae575b505050505093508280548060200260200160405190810160405280929190818152602001828054801561151e57602002820191906000526020600020905b81548152602001906001019080831161150a575b5050505050925081805480602002602001604051908101604052809291908181526020016000905b828210156115f2578382906000526020600020018054611565906168b1565b80601f0160208091040260200160405190810160405280929190818152602001828054611591906168b1565b80156115de5780601f106115b3576101008083540402835291602001916115de565b820191906000526020600020905b8154815290600101906020018083116115c157829003601f168201915b505050505081526020019060010190611546565b50505050915080805480602002602001604051908101604052809291908181526020016000905b828210156116c5578382906000526020600020018054611638906168b1565b80601f0160208091040260200160405190810160405280929190818152602001828054611664906168b1565b80156116b15780601f10611686576101008083540402835291602001916116b1565b820191906000526020600020905b81548152906001019060200180831161169457829003601f168201915b505050505081526020019060010190611619565b5050505090509450945094509450509193509193565b604080517f150214d74d59b7d1e90c73fc22ef3d991dd0a76b046543d4d80ab92d2a50328f602082015290810186905260ff8516606082015260009081906117299061103b90608001611020565b90506117468782886040518060200160405280600081525061341e565b979650505050505050565b6000610f9982613441565b60008060008061176b8561358e565b935093509350935061177f84848484611808565b505050505050565b600054630100000090046001600160a01b031633146117b9576040516306fbb1e360e01b815260040160405180910390fd5b6001600160a01b0381166000818152600160208190526040808320805460ff1916909217909155517f7fd26be6fc92aff63f1f4409b2b2ddeb272a888031d7f55ec830485ec61941869190a250565b60006113278585858561381f565b600054630100000090046001600160a01b03163314611848576040516306fbb1e360e01b815260040160405180910390fd5b6001600160a01b038116600081815260016020526040808220805460ff19169055517fe0db3499b7fdc3da4cddff5f45d694549c19835e7f719fb5606d3ad1a5de40119190a250565b6101f85460408051634bf5d7e960e01b815290516060926001600160a01b031691634bf5d7e99160048083019260009291908290030181865afa9250505080156118fd57506040513d6000823e601f3d908101601f191682016040526118fa9190810190616997565b60015b611939575060408051808201909152601d81527f6d6f64653d626c6f636b6e756d6265722666726f6d3d64656661756c74000000602082015290565b919050565b60008033905061195f8482856040518060200160405280600081525061341e565b949350505050565b60008033905061174687828888888080601f0160208091040260200160405190810160405280939291908181526020018383808284376000920191909152508a9250612dc8915050565b61025e546000908082036119ca57505061025d54919050565b600061025e6119da600184616a04565b815481106119ea576119ea6168eb565b60009182526020918290206040805180820190915291015463ffffffff8116808352600160201b9091046001600160e01b03169282019290925291508410611a4057602001516001600160e01b03169392505050565b611a55611a4c856138ea565b61025e90613953565b6001600160e01b0316949350505050565b611a6e610eb9565b6001600160a01b0316336001600160a01b031614611a9e5760405162461bcd60e51b81526004016104489061687a565b30611aa7610eb9565b6001600160a01b031614611ae55760008036604051611ac792919061686a565b604051809103902090505b80611ade610164612e6b565b03611ad257505b6111af81613a06565b600080339050611b3686828787878080601f01602080910402602001604051908101604052809392919081815260200183838082843760009201919091525061341e92505050565b9695505050505050565b6000805462010000900460ff1615611b6b57604051631785c68160e01b815260040160405180910390fd5b3360009081526001602052604090205460ff1615611b9c5760405163b1d02c3d60e01b815260040160405180910390fd5b611ba4613a49565b3360009081526102c360205260409020548015611c19576000611bc682611751565b90506001816007811115611bdc57611bdc616307565b1480611bf957506000816007811115611bf757611bf7616307565b145b15611c175760405163867f3ee560e01b815260040160405180910390fd5b505b825160208401206000611c2e88888885612a09565b3360009081526102c3602052604090208190559050611c4f88888888613af4565b98975050505050505050565b600054610100900460ff1615808015611c7b5750600054600160ff909116105b80611c955750303b158015611c95575060005460ff166001145b611cf85760405162461bcd60e51b815260206004820152602e60248201527f496e697469616c697a61626c653a20636f6e747261637420697320616c72656160448201526d191e481a5b9a5d1a585b1a5e995960921b6064820152608401610448565b6000805460ff191660011790558015611d1b576000805461ff0019166101001790555b334114611d3b5760405163022d8c9560e31b815260040160405180910390fd5b3a15611d5a576040516383f1b1d360e01b815260040160405180910390fd5b611d866040518060400160405280600b81526020016a2129a1a3b7bb32b93737b960a91b815250613b5c565b611db2611d9560036000616a2d565b611da3600362093a80616a2d565b680ad78ebc5ac6200000613bb3565b611dba613bea565b611dc5612005613c11565b611dd0612006613c41565b611dda600a613c71565b611df0611deb600362015180616a2d565b613ca1565b6110076000526102c16020527f2f832952f0ef896b8c8edd6d16a2e4f2591a90375e33021e3b9ff197f3793fc0805460ff19166001179055611e457308e68ec70fa3b629784fdb28887e206ce8561e08613cd1565b80156111af576000805461ff0019169055604051600181527f7f26b83ff96e1f2b6a682f133852f6798a09c465da95921460cefb38474024989060200160405180910390a150565b600054630100000090046001600160a01b03163314611ebf576040516306fbb1e360e01b815260040160405180910390fd5b60005462010000900460ff1615611ee957604051631785c68160e01b815260040160405180910390fd5b6000805462ff00001916620100001781556040517f9e87fac88ff661f02d44f95383c817fece4bce600a3dab7a54406878b965e7529190a1565b6000606080600080600060606098546000801b148015611f435750609954155b611f875760405162461bcd60e51b81526020600482015260156024820152741152540dcc4c8e88155b9a5b9a5d1a585b1a5e9959605a1b6044820152606401610448565b611f8f613d24565b611f97613d33565b60408051600080825260208201909252600f60f81b9b939a50919850469750309650945092509050565b6101f854604080516324776b7d60e21b815290516000926001600160a01b0316916391ddadf49160048083019260209291908290030181865afa925050508015612028575060408051601f3d908101601f1916820190925261202591810190616a4f565b60015b61193957610ece43613d42565b6000612042848484613da9565b90505b9392505050565b61025e54600090156120715761206361025e613e20565b6001600160e01b0316905090565b5061025d5490565b612081610eb9565b6001600160a01b0316336001600160a01b0316146120b15760405162461bcd60e51b81526004016104489061687a565b306120ba610eb9565b6001600160a01b0316146120f857600080366040516120da92919061686a565b604051809103902090505b806120f1610164612e6b565b036120e557505b6111af81613e50565b61022b54600082815261022c602052604080822054905163d45c443560e01b81526004810191909152909182916001600160a01b039091169063d45c443590602401602060405180830381865afa158015612160573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906121849190616a77565b9050806001146121945780612045565b60009392505050565b33611007146121c357604051630f22c43960e41b81526110076004820152602401610448565b6122296040518060400160405280600b81526020016a766f74696e6744656c617960a81b81525085858080601f0160208091040260200160405190810160405280939291908181526020018383808284376000920191909152509293925050613ebb9050565b156122de57602081146122575783838383604051630a5a604160e01b81526004016104489493929190616ab9565b604080516020601f8401819004810282018101909252828152600091612298918585808385018382808284376000920191909152509293925050613f149050565b90508015806122a957506201518081115b156122cf5784848484604051630a5a604160e01b81526004016104489493929190616ab9565b6122d881613a06565b5061289f565b6123456040518060400160405280600c81526020016b1d9bdd1a5b99d4195c9a5bd960a21b81525085858080601f0160208091040260200160405190810160405280939291908181526020018383808284376000920191909152509293925050613ebb9050565b156123f457602081146123735783838383604051630a5a604160e01b81526004016104489493929190616ab9565b604080516020601f84018190048102820181019092528281526000916123b4918585808385018382808284376000920191909152509293925050613f149050565b90508015806123c5575062278d0081115b156123eb5784848484604051630a5a604160e01b81526004016104489493929190616ab9565b6122d881613f19565b612460604051806040016040528060118152602001701c1c9bdc1bdcd85b151a1c995cda1bdb19607a1b81525085858080601f0160208091040260200160405190810160405280939291908181526020018383808284376000920191909152509293925050613ebb9050565b15612516576020811461248e5783838383604051630a5a604160e01b81526004016104489493929190616ab9565b604080516020601f84018190048102820181019092528281526000916124cf918585808385018382808284376000920191909152509293925050613f149050565b90508015806124e7575069021e19e0c9bab240000081115b1561250d5784848484604051630a5a604160e01b81526004016104489493929190616ab9565b6122d881613fbc565b6125806040518060400160405280600f81526020016e38bab7b93ab6a73ab6b2b930ba37b960891b81525085858080601f0160208091040260200160405190810160405280939291908181526020018383808284376000920191909152509293925050613ebb9050565b1561262f57602081146125ae5783838383604051630a5a604160e01b81526004016104489493929190616ab9565b604080516020601f84018190048102820181019092528281526000916125ef918585808385018382808284376000920191909152509293925050613f149050565b905060058110806126005750601481115b156126265784848484604051630a5a604160e01b81526004016104489493929190616ab9565b6122d881612eea565b61269e604051806040016040528060148152602001736d696e506572696f64416674657251756f72756d60601b81525085858080601f0160208091040260200160405190810160405280939291908181526020018383808284376000920191909152509293925050613ebb9050565b1561276457600881146126cc5783838383604051630a5a604160e01b81526004016104489493929190616ab9565b6000612712600884848080601f0160208091040260200160405190810160405280939291908181526020018383808284376000920191909152509293925050613f149050565b90506001600160401b038116158061273557506202a300816001600160401b0316115b1561275b5784848484604051630a5a604160e01b81526004016104489493929190616ab9565b6122d881613fff565b6127d06040518060400160405280601181526020017033b7bb32b93737b9283937ba32b1ba37b960791b81525085858080601f0160208091040260200160405190810160405280939291908181526020018383808284376000920191909152509293925050613ebb9050565b1561287e57601481146127fe5783838383604051630a5a604160e01b81526004016104489493929190616ab9565b6000612844601484848080601f0160208091040260200160405190810160405280939291908181526020018383808284376000920191909152509293925050613f149050565b90506001600160a01b0381166128755784848484604051630a5a604160e01b81526004016104489493929190616ab9565b6122d88161406b565b838383836040516325ee20d560e21b81526004016104489493929190616ab9565b7ff1ce9b2cbf50eeb05769a29e2543fd350cab46894a7dd9978a12d534bb20e633848484846040516128d49493929190616ab9565b60405180910390a150505050565b6000610ece6101965490565b6000610f99826140d7565b612901610eb9565b6001600160a01b0316336001600160a01b0316146129315760405162461bcd60e51b81526004016104489061687a565b3061293a610eb9565b6001600160a01b031614612978576000803660405161295a92919061686a565b604051809103902090505b80612971610164612e6b565b0361296557505b600080856001600160a01b031685858560405161299692919061686a565b60006040518083038185875af1925050503d80600081146129d3576040519150601f19603f3d011682016040523d82523d6000602084013e6129d8565b606091505b5091509150612a008282604051806060016040528060288152602001616f1660289139614115565b50505050505050565b600084848484604051602001612a229493929190616ae0565b60408051601f19818403018152919052805160209091012095945050505050565b612a4b610eb9565b6001600160a01b0316336001600160a01b031614612a7b5760405162461bcd60e51b81526004016104489061687a565b30612a84610eb9565b6001600160a01b031614612ac25760008036604051612aa492919061686a565b604051809103902090505b80612abb610164612e6b565b03612aaf57505b6111af81613fff565b60008251845114612b2f5760405162461bcd60e51b815260206004820152602860248201527f476f7665726e6f72427261766f3a20696e76616c6964207369676e61747572656044820152670e640d8cadccee8d60c31b6064820152608401610448565b612b3d33878787878761412e565b611b368686612b4c87876141ec565b85611b40565b600080600080612b618561358e565b935093509350935061177f84848484611245565b612b7d610eb9565b6001600160a01b0316336001600160a01b031614612bad5760405162461bcd60e51b81526004016104489061687a565b30612bb6610eb9565b6001600160a01b031614612bf45760008036604051612bd692919061686a565b604051809103902090505b80612bed610164612e6b565b03612be157505b6111af81613f19565b60006120458383612c1960408051602081019091526000815290565b613da9565b612c26610eb9565b6001600160a01b0316336001600160a01b031614612c565760405162461bcd60e51b81526004016104489061687a565b30612c5f610eb9565b6001600160a01b031614612c9d5760008036604051612c7f92919061686a565b604051809103902090505b80612c96610164612e6b565b03612c8a57505b6111af81613fbc565b60006064612cb3836119b1565b6101f854604051632394e7a360e21b8152600481018690526001600160a01b0390911690638e539e8c90602401602060405180830381865afa158015612cfd573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612d219190616a77565b612d2b9190616b2b565b610f999190616a2d565b600080600080612d448561358e565b935093509350935061177f84848484611356565b60006001600160e01b03198216636e665ced60e01b1480610f995750610f998261431e565b6000610f99612d8a6143ba565b8360405161190160f01b8152600281019290925260228201526042902090565b6000806000612dbb878787876143c4565b9150915061143f81614488565b6000805462010000900460ff1615612df357604051631785c68160e01b815260040160405180910390fd5b3360009081526001602052604090205460ff1615612e245760405163b1d02c3d60e01b815260040160405180910390fd5b6001600160a01b03851660009081526001602052604090205460ff1615612e5e5760405163b1d02c3d60e01b815260040160405180910390fd5b611b3686868686866145d2565b6000612e868254600f81810b600160801b909204900b131590565b15612ea457604051631ed9509560e11b815260040160405180910390fd5b508054600f0b6000818152600180840160205260408220805492905583546fffffffffffffffffffffffffffffffff191692016001600160801b03169190911790915590565b6064811115612f6d5760405162461bcd60e51b815260206004820152604360248201527f476f7665726e6f72566f74657351756f72756d4672616374696f6e3a2071756f60448201527f72756d4e756d657261746f72206f7665722071756f72756d44656e6f6d696e616064820152623a37b960e91b608482015260a401610448565b6000612f7761204c565b90508015801590612f89575061025e54155b15612fee57604080518082019091526000815261025e9060208101612fad846146d5565b6001600160e01b039081169091528254600181018455600093845260209384902083519490930151909116600160201b0263ffffffff909316929092179101555b61301c613009612ffc611fc1565b65ffffffffffff166138ea565b613012846146d5565b61025e919061473e565b505060408051828152602081018490527f0553476bf02ef2726e8ce5ced78d63e26e602e4a2257b1f559418e24b4633997910160405180910390a15050565b60008061306a86868686612a09565b9050600461307782611751565b600781111561308857613088616307565b146130a55760405162461bcd60e51b815260040161044890616956565b61022b546040805163793d064960e11b815290516000926001600160a01b03169163f27a0c929160048083019260209291908290030181865afa1580156130f0573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906131149190616a77565b61022b5460405163b1c5f42760e01b81529192506001600160a01b03169063b1c5f4279061314f908a908a908a906000908b90600401616b42565b602060405180830381865afa15801561316c573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906131909190616a77565b600083815261022c60205260408082209290925561022b5491516308f2a0bb60e41b81526001600160a01b0390921691638f2a0bb0916131dd918b918b918b91908b908990600401616b90565b600060405180830381600087803b1580156131f757600080fd5b505af115801561320b573d6000803e3d6000fd5b505050507f9a2e42fd6722813d69113e7d0079d3d940171428df7373df9c7f7617cfda289282824261323d9190616be8565b604080519283526020830191909152015b60405180910390a15095945050505050565b30613269610eb9565b6001600160a01b0316146132fa5760005b845181101561177f57306001600160a01b031685828151811061329f5761329f6168eb565b60200260200101516001600160a01b0316036132ea576132ea8382815181106132ca576132ca6168eb565b60200260200101518051906020012061016461475990919063ffffffff16565b6132f381616917565b905061327a565b5050505050565b60005462010000900460ff161561332b57604051631785c68160e01b815260040160405180910390fd5b3360009081526001602052604090205460ff161561335c5760405163b1d02c3d60e01b815260040160405180910390fd5b60005b84518110156133d5576102c1600086838151811061337f5761337f6168eb565b6020908102919091018101516001600160a01b031682528101919091526040016000205460ff166133c357604051630b094f2760e31b815260040160405180910390fd5b806133cd81616917565b91505061335f565b506132fa8585858585614795565b306133ec610eb9565b6001600160a01b0316146132fa5761016454600f81810b600160801b909204900b13156132fa576000610164556132fa565b60006113278585858561343c60408051602081019091526000815290565b612dc8565b60008061344d8361480a565b9050600481600781111561346357613463616307565b1461346e5792915050565b600083815261022c60205260409020548061348a575092915050565b61022b54604051632ab0f52960e01b8152600481018390526001600160a01b0390911690632ab0f52990602401602060405180830381865afa1580156134d4573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906134f89190616bfb565b15613507575060079392505050565b61022b54604051632c258a9f60e11b8152600481018390526001600160a01b039091169063584b153e90602401602060405180830381865afa158015613551573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906135759190616bfb565b15613584575060059392505050565b5060029392505050565b60608060606000806101c660008781526020019081526020016000209050806001018160020161376083600301805480602002602001604051908101604052809291908181526020016000905b828210156136875783829060005260206000200180546135fa906168b1565b80601f0160208091040260200160405190810160405280929190818152602001828054613626906168b1565b80156136735780601f1061364857610100808354040283529160200191613673565b820191906000526020600020905b81548152906001019060200180831161365657829003601f168201915b5050505050815260200190600101906135db565b50505060048601805460408051602080840282018101909252828152935060009084015b828210156137575783829060005260206000200180546136ca906168b1565b80601f01602080910402602001604051908101604052809291908181526020018280546136f6906168b1565b80156137435780601f1061371857610100808354040283529160200191613743565b820191906000526020600020905b81548152906001019060200180831161372657829003601f168201915b5050505050815260200190600101906136ab565b505050506141ec565b60098401548354604080516020808402820181019092528281529186918301828280156137b657602002820191906000526020600020905b81546001600160a01b03168152600190910190602001808311613798575b505050505093508280548060200260200160405190810160405280929190818152602001828054801561380857602002820191906000526020600020905b8154815260200190600101908083116137f4575b505050505092509450945094509450509193509193565b60008061382e86868686612a09565b60008181526101c660205260409020549091506001600160a01b031633811480613882575061385b6128e2565b613880826001613869611fc1565b6138739190616930565b65ffffffffffff16612bfd565b105b6138de5760405162461bcd60e51b815260206004820152602760248201527f476f7665726e6f72427261766f3a2070726f706f7365722061626f76652074686044820152661c995cda1bdb1960ca1b6064820152608401610448565b61174687878787614942565b600063ffffffff82111561394f5760405162461bcd60e51b815260206004820152602660248201527f53616665436173743a2076616c756520646f65736e27742066697420696e203360448201526532206269747360d01b6064820152608401610448565b5090565b8154600090818160058111156139b057600061396e84614950565b6139789085616a04565b60008881526020902090915081015463ffffffff90811690871610156139a0578091506139ae565b6139ab816001616be8565b92505b505b60006139be87878585614a38565b905080156139f9576139e3876139d5600184616a04565b600091825260209091200190565b54600160201b90046001600160e01b0316611746565b6000979650505050505050565b6101945460408051918252602082018390527fc565b045403dc03c2eea82b81a0465edad9e2e7fc4d97e11421c209da93d7a93910160405180910390a161019455565b6102c25460ff16613af2576a084595161401484a0000006120056001600160a01b03166318160ddd6040518163ffffffff1660e01b8152600401602060405180830381865afa158015613aa0573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613ac49190616a77565b1015613ae3576040516311b6707f60e01b815260040160405180910390fd5b6102c2805460ff191660011790555b565b6000613b5033868686516001600160401b03811115613b1557613b15615d3f565b604051908082528060200260200182016040528015613b4857816020015b6060815260200190600190039081613b335790505b50878761412e565b61132785858585614a8e565b600054610100900460ff16613b835760405162461bcd60e51b815260040161044890616c1d565b613baa81613ba56040805180820190915260018152603160f81b602082015290565b614e6d565b6111af81614ebc565b600054610100900460ff16613bda5760405162461bcd60e51b815260040161044890616c1d565b613be5838383614ef4565b505050565b600054610100900460ff16613af25760405162461bcd60e51b815260040161044890616c1d565b600054610100900460ff16613c385760405162461bcd60e51b815260040161044890616c1d565b6111af81614f36565b600054610100900460ff16613c685760405162461bcd60e51b815260040161044890616c1d565b6111af81614f80565b600054610100900460ff16613c985760405162461bcd60e51b815260040161044890616c1d565b6111af81614fa7565b600054610100900460ff16613cc85760405162461bcd60e51b815260040161044890616c1d565b6111af81614fce565b600054610100900460ff16613cf85760405162461bcd60e51b815260040161044890616c1d565b600080546001600160a01b039092166301000000026301000000600160b81b0319909216919091179055565b6060609a80546111c2906168b1565b6060609b80546111c2906168b1565b600065ffffffffffff82111561394f5760405162461bcd60e51b815260206004820152602660248201527f53616665436173743a2076616c756520646f65736e27742066697420696e203460448201526538206269747360d01b6064820152608401610448565b6101f854604051630748d63560e31b81526001600160a01b038581166004830152602482018590526000921690633a46b1a890604401602060405180830381865afa158015613dfc573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906120429190616a77565b8054600090801561219457613e3a836139d5600184616a04565b54600160201b90046001600160e01b0316612045565b61022b54604080516001600160a01b03928316815291831660208301527f08f74ea46ef7894f65eabfb5e6e695de773a000b47c529ab559178069b226401910160405180910390a161022b80546001600160a01b0319166001600160a01b0392909216919091179055565b600081604051602001613ece9190616c68565b6040516020818303038152906040528051906020012083604051602001613ef59190616c68565b6040516020818303038152906040528051906020012014905092915050565b015190565b60008111613f795760405162461bcd60e51b815260206004820152602760248201527f476f7665726e6f7253657474696e67733a20766f74696e6720706572696f6420604482015266746f6f206c6f7760c81b6064820152608401610448565b6101955460408051918252602082018390527f7e3f7f0708a84de9203036abaa450dccc85ad5ff52f78c170f3edb55cf5e8828910160405180910390a161019555565b6101965460408051918252602082018390527fccb45da8d5717e6c4544694297c4ba5cf151d455c9bb0ed4fc7a38411bc05461910160405180910390a161019655565b61028f54604080516001600160401b03928316815291831660208301527f7ca4ac117ed3cdce75c1161d8207c440389b1a15d69d096831664657c07dafc2910160405180910390a161028f805467ffffffffffffffff19166001600160401b0392909216919091179055565b600080546040516001600160a01b0380851693630100000090930416917f44fc1b38a4abaa91ebd1b628a5b259a698f86238c8217d68f516e87769c60c0b91a3600080546001600160a01b039092166301000000026301000000600160b81b0319909216919091179055565b60008181526101636020526040812060010154610f99906001600160401b0316600084815261029060205260409020546001600160401b0316614ff5565b60608315614124575081612045565b612045838361500b565b80516020820120600061414c878761414688886141ec565b85612a09565b60008181526101c6602052604090206009810154919250906141e15780546001600160a01b0319166001600160a01b038a16178155875161419690600183019060208b0190615ada565b5086516141ac90600283019060208a0190615b3b565b5085516141c29060038301906020890190615b76565b5084516141d89060048301906020880190615bc8565b50600981018390555b505050505050505050565b6060600082516001600160401b0381111561420957614209615d3f565b60405190808252806020026020018201604052801561423c57816020015b60608152602001906001900390816142275790505b50905060005b81518110156143165784818151811061425d5761425d6168eb565b6020026020010151516000146142cd5784818151811061427f5761427f6168eb565b6020026020010151805190602001208482815181106142a0576142a06168eb565b60200260200101516040516020016142b9929190616c84565b6040516020818303038152906040526142e8565b8381815181106142df576142df6168eb565b60200260200101515b8282815181106142fa576142fa6168eb565b60200260200101819052508061430f90616917565b9050614242565b509392505050565b600063288ace0360e11b6318df743f60e31b63bf26d89760e01b6379dd796f60e01b6001600160e01b0319861682148061436457506001600160e01b0319868116908216145b8061437b57506001600160e01b0319868116908516145b8061439657506001600160e01b03198616630271189760e51b145b80611b3657506301ffc9a760e01b6001600160e01b03198716149695505050505050565b6000610ece615035565b6000807f7fffffffffffffffffffffffffffffff5d576e7357a4501ddfe92f46681b20a08311156143fb575060009050600361447f565b6040805160008082526020820180845289905260ff881692820192909252606081018690526080810185905260019060a0016020604051602081039080840390855afa15801561444f573d6000803e3d6000fd5b5050604051601f1901519150506001600160a01b0381166144785760006001925092505061447f565b9150600090505b94509492505050565b600081600481111561449c5761449c616307565b036144a45750565b60018160048111156144b8576144b8616307565b036145055760405162461bcd60e51b815260206004820152601860248201527f45434453413a20696e76616c6964207369676e617475726500000000000000006044820152606401610448565b600281600481111561451957614519616307565b036145665760405162461bcd60e51b815260206004820152601f60248201527f45434453413a20696e76616c6964207369676e6174757265206c656e677468006044820152606401610448565b600381600481111561457a5761457a616307565b036111af5760405162461bcd60e51b815260206004820152602260248201527f45434453413a20696e76616c6964207369676e6174757265202773272076616c604482015261756560f01b6064820152608401610448565b6000806145e287878787876150a9565b600088815261029060205260409020549091506001600160401b031615801561460f575061460f876151ff565b15611b3657600061462961028f546001600160401b031690565b614631611fc1565b65ffffffffffff166146439190616cb5565b905061464e886128ee565b816001600160401b0316111561469d576040516001600160401b038216815288907f541f725fb9f7c98a30cc9c0ff32fbb14358cd7159c847a3aa20a2bdc442ba5119060200160405180910390a25b600088815261029060205260409020805467ffffffffffffffff19166001600160401b03929092169190911790559695505050505050565b60006001600160e01b0382111561394f5760405162461bcd60e51b815260206004820152602760248201527f53616665436173743a2076616c756520646f65736e27742066697420696e20326044820152663234206269747360c81b6064820152608401610448565b60008061474c85858561523f565b915091505b935093915050565b8154600160801b90819004600f0b6000818152600180860160205260409091209390935583546001600160801b03908116939091011602179055565b61022b5460405163e38335e560e01b81526001600160a01b039091169063e38335e59034906147d1908890889088906000908990600401616b42565b6000604051808303818588803b1580156147ea57600080fd5b505af11580156147fe573d6000803e3d6000fd5b50505050505050505050565b600081815261016360205260408120600281015460ff161561482f5750600792915050565b6002810154610100900460ff161561484a5750600292915050565b600083815261016360205260408120546001600160401b0316908190036148b35760405162461bcd60e51b815260206004820152601d60248201527f476f7665726e6f723a20756e6b6e6f776e2070726f706f73616c2069640000006044820152606401610448565b60006148bd611fc1565b65ffffffffffff1690508082106148d957506000949350505050565b60006148e4866128ee565b90508181106148f95750600195945050505050565b614902866151ff565b8015614925575060008681526101c6602052604090206006810154600590910154115b156149365750600495945050505050565b50600395945050505050565b6000611327858585856153de565b60008160000361496257506000919050565b6000600161496f84615494565b901c6001901b9050600181848161498857614988616a17565b048201901c905060018184816149a0576149a0616a17565b048201901c905060018184816149b8576149b8616a17565b048201901c905060018184816149d0576149d0616a17565b048201901c905060018184816149e8576149e8616a17565b048201901c90506001818481614a0057614a00616a17565b048201901c90506001818481614a1857614a18616a17565b048201901c905061204581828581614a3257614a32616a17565b04615528565b60005b81831015614316576000614a4f8484615537565b60008781526020902090915063ffffffff86169082015463ffffffff161115614a7a57809250614a88565b614a85816001616be8565b93505b50614a3b565b600033614a9b8184615552565b614ae75760405162461bcd60e51b815260206004820152601d60248201527f476f7665726e6f723a2070726f706f73657220726573747269637465640000006044820152606401610448565b6000614af1611fc1565b65ffffffffffff169050614b036128e2565b614b1283610e14600185616a04565b1015614b7a5760405162461bcd60e51b815260206004820152603160248201527f476f7665726e6f723a2070726f706f73657220766f7465732062656c6f7720706044820152701c9bdc1bdcd85b081d1a1c995cda1bdb19607a1b6064820152608401610448565b6000614b8f8888888880519060200120612a09565b90508651885114614bb25760405162461bcd60e51b815260040161044890616cd5565b8551885114614bd35760405162461bcd60e51b815260040161044890616cd5565b6000885111614c245760405162461bcd60e51b815260206004820152601860248201527f476f7665726e6f723a20656d7074792070726f706f73616c00000000000000006044820152606401610448565b600081815261016360205260409020546001600160401b031615614c945760405162461bcd60e51b815260206004820152602160248201527f476f7665726e6f723a2070726f706f73616c20616c72656164792065786973746044820152607360f81b6064820152608401610448565b6000614ca06101945490565b614caa9084616be8565b90506000614cb86101955490565b614cc29083616be8565b90506040518060e00160405280614cd884615643565b6001600160401b031681526001600160a01b038716602082015260006040820152606001614d0583615643565b6001600160401b03908116825260006020808401829052604080850183905260609485018390528883526101638252918290208551815492870151878501519186166001600160e01b031990941693909317600160401b6001600160a01b039094168402176001600160e01b0316600160e01b60e09290921c91909102178155938501516080860151908416921c0217600183015560a08301516002909201805460c09094015161ffff1990941692151561ff00191692909217610100931515939093029290921790558a517f7d84a6263ae0d98d3329bd7b46bb4e8d6f98cd35a7adb45c274c8b7fd5ebd5e091859188918e918e91811115614e0a57614e0a615d3f565b604051908082528060200260200182016040528015614e3d57816020015b6060815260200190600190039081614e285790505b508d88888f604051614e5799989796959493929190616d16565b60405180910390a1509098975050505050505050565b600054610100900460ff16614e945760405162461bcd60e51b815260040161044890616c1d565b609a614ea08382616df4565b50609b614ead8282616df4565b50506000609881905560995550565b600054610100900460ff16614ee35760405162461bcd60e51b815260040161044890616c1d565b610162614ef08282616df4565b5050565b600054610100900460ff16614f1b5760405162461bcd60e51b815260040161044890616c1d565b614f2483613a06565b614f2d82613f19565b613be581613fbc565b600054610100900460ff16614f5d5760405162461bcd60e51b815260040161044890616c1d565b6101f880546001600160a01b0319166001600160a01b0392909216919091179055565b600054610100900460ff166120f85760405162461bcd60e51b815260040161044890616c1d565b600054610100900460ff166111a65760405162461bcd60e51b815260040161044890616c1d565b600054610100900460ff16612ac25760405162461bcd60e51b815260040161044890616c1d565b60008183116150045781612045565b5090919050565b81511561501b5781518083602001fd5b8060405162461bcd60e51b81526004016104489190615ef8565b60007f8b73c3c69bb8fe3d512ecc4cf759cc79239f7b179b0ffacaa9a75d522b39400f6150606156ab565b615068615704565b60408051602081019490945283019190915260608201524660808201523060a082015260c00160405160208183030381529060405280519060200120905090565b60008581526101636020526040812060016150c388611751565b60078111156150d4576150d4616307565b1461512d5760405162461bcd60e51b815260206004820152602360248201527f476f7665726e6f723a20766f7465206e6f742063757272656e746c792061637460448201526269766560e81b6064820152608401610448565b80546000906151479088906001600160401b031686613da9565b90506151568888888488615735565b83516000036151ab57866001600160a01b03167fb8e138887d0aa13bab447e82de9d5c1777041ecd21ca36ba824ff1e6c07ddda48988848960405161519e9493929190616eb3565b60405180910390a2611746565b866001600160a01b03167fe2babfbac5889a709b63bb7f598b324e08bc5a4fb9ec647fb3cbc9ec07eb871289888489896040516151ec959493929190616edb565b60405180910390a2979650505050505050565b60008181526101c6602052604081206005810154615236610e8085600090815261016360205260409020546001600160401b031690565b11159392505050565b82546000908190801561538557600061525d876139d5600185616a04565b60408051808201909152905463ffffffff808216808452600160201b9092046001600160e01b0316602084015291925090871610156152de5760405162461bcd60e51b815260206004820152601b60248201527f436865636b706f696e743a2064656372656173696e67206b65797300000000006044820152606401610448565b805163ffffffff80881691160361532657846152ff886139d5600186616a04565b80546001600160e01b0392909216600160201b0263ffffffff909216919091179055615375565b6040805180820190915263ffffffff80881682526001600160e01b0380881660208085019182528b54600181018d5560008d81529190912094519151909216600160201b029216919091179101555b6020015192508391506147519050565b50506040805180820190915263ffffffff80851682526001600160e01b0380851660208085019182528854600181018a5560008a815291822095519251909316600160201b029190931617920191909155905081614751565b6000806153ed868686866158d3565b600081815261022c6020526040902054909150156113275761022b54600082815261022c60205260409081902054905163c4d252f560e01b81526001600160a01b039092169163c4d252f5916154499160040190815260200190565b600060405180830381600087803b15801561546357600080fd5b505af1158015615477573d6000803e3d6000fd5b505050600082815261022c60205260408120555095945050505050565b600080608083901c156154a957608092831c92015b604083901c156154bb57604092831c92015b602083901c156154cd57602092831c92015b601083901c156154df57601092831c92015b600883901c156154f157600892831c92015b600483901c1561550357600492831c92015b600283901c1561551557600292831c92015b600183901c15610f995760010192915050565b60008183106150045781612045565b60006155466002848418616a2d565b61204590848416616be8565b8051600090603481101561556a576001915050610f99565b82810160131901516001600160a01b031981166b046e0e4dee0dee6cae47a60f60a31b1461559d57600192505050610f99565b6000806155ab602885616a04565b90505b83811015615622576000806155e28884815181106155ce576155ce6168eb565b01602001516001600160f81b0319166159e0565b91509150816155fa5760019650505050505050610f99565b8060ff166004856001600160a01b0316901b17935050508061561b90616917565b90506155ae565b50856001600160a01b0316816001600160a01b031614935050505092915050565b60006001600160401b0382111561394f5760405162461bcd60e51b815260206004820152602660248201527f53616665436173743a2076616c756520646f65736e27742066697420696e203660448201526534206269747360d01b6064820152608401610448565b6000806156b6613d24565b8051909150156156cd578051602090910120919050565b60985480156156dc5792915050565b7fc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a4709250505090565b60008061570f613d33565b805190915015615726578051602090910120919050565b60995480156156dc5792915050565b60008581526101c6602090815260408083206001600160a01b038816845260088101909252909120805460ff16156157c55760405162461bcd60e51b815260206004820152602d60248201527f476f7665726e6f72436f6d7061746962696c697479427261766f3a20766f746560448201526c08185b1c9958591e4818d85cdd609a1b6064820152608401610448565b805460ff86166101000261ffff199091161760011781556157e584615a72565b81546001600160601b039190911662010000026dffffffffffffffffffffffff00001990911617815560ff8516615835578382600601600082825461582a9190616be8565b90915550612a009050565b60001960ff861601615855578382600501600082825461582a9190616be8565b60011960ff861601615875578382600701600082825461582a9190616be8565b60405162461bcd60e51b815260206004820152602d60248201527f476f7665726e6f72436f6d7061746962696c697479427261766f3a20696e766160448201526c6c696420766f7465207479706560981b6064820152608401610448565b6000806158e286868686612a09565b905060006158ef82611751565b9050600281600781111561590557615905616307565b141580156159255750600681600781111561592257615922616307565b14155b80156159435750600781600781111561594057615940616307565b14155b61598f5760405162461bcd60e51b815260206004820152601d60248201527f476f7665726e6f723a2070726f706f73616c206e6f74206163746976650000006044820152606401610448565b6000828152610163602052604090819020600201805461ff001916610100179055517f789cf55be980739dad1d0699b93b58e806b51c9d96619bfa8fe0a28abaa7b30c9061324e9084815260200190565b60008060f883901c602f811180156159fb5750603a8160ff16105b15615a1057600194602f199091019350915050565b8060ff166040108015615a26575060478160ff16105b15615a3b576001946036199091019350915050565b8060ff166060108015615a51575060678160ff16105b15615a66576001946056199091019350915050565b50600093849350915050565b60006001600160601b0382111561394f5760405162461bcd60e51b815260206004820152602660248201527f53616665436173743a2076616c756520646f65736e27742066697420696e203960448201526536206269747360d01b6064820152608401610448565b828054828255906000526020600020908101928215615b2f579160200282015b82811115615b2f57825182546001600160a01b0319166001600160a01b03909116178255602090920191600190910190615afa565b5061394f929150615c1a565b828054828255906000526020600020908101928215615b2f579160200282015b82811115615b2f578251825591602001919060010190615b5b565b828054828255906000526020600020908101928215615bbc579160200282015b82811115615bbc5782518290615bac9082616df4565b5091602001919060010190615b96565b5061394f929150615c2f565b828054828255906000526020600020908101928215615c0e579160200282015b82811115615c0e5782518290615bfe9082616df4565b5091602001919060010190615be8565b5061394f929150615c4c565b5b8082111561394f5760008155600101615c1b565b8082111561394f576000615c438282615c69565b50600101615c2f565b8082111561394f576000615c608282615c69565b50600101615c4c565b508054615c75906168b1565b6000825580601f10615c85575050565b601f0160209004906000526020600020908101906111af9190615c1a565b600060208284031215615cb557600080fd5b5035919050565b600060208284031215615cce57600080fd5b81356001600160e01b03198116811461204557600080fd5b803560ff8116811461193957600080fd5b60008083601f840112615d0957600080fd5b5081356001600160401b03811115615d2057600080fd5b602083019150836020828501011115615d3857600080fd5b9250929050565b634e487b7160e01b600052604160045260246000fd5b604051601f8201601f191681016001600160401b0381118282101715615d7d57615d7d615d3f565b604052919050565b60006001600160401b03821115615d9e57615d9e615d3f565b50601f01601f191660200190565b600082601f830112615dbd57600080fd5b8135615dd0615dcb82615d85565b615d55565b818152846020838601011115615de557600080fd5b816020850160208301376000918101602001919091529392505050565b60008060008060008060008060e0898b031215615e1e57600080fd5b88359750615e2e60208a01615ce6565b965060408901356001600160401b0380821115615e4a57600080fd5b615e568c838d01615cf7565b909850965060608b0135915080821115615e6f57600080fd5b50615e7c8b828c01615dac565b945050615e8b60808a01615ce6565b925060a0890135915060c089013590509295985092959890939650565b60005b83811015615ec3578181015183820152602001615eab565b50506000910152565b60008151808452615ee4816020860160208601615ea8565b601f01601f19169290920160200192915050565b6020815260006120456020830184615ecc565b6001600160a01b03811681146111af57600080fd5b60008060008060808587031215615f3657600080fd5b8435615f4181615f0b565b93506020850135615f5181615f0b565b92506040850135915060608501356001600160401b03811115615f7357600080fd5b615f7f87828801615dac565b91505092959194509250565b60006001600160401b03821115615fa457615fa4615d3f565b5060051b60200190565b600082601f830112615fbf57600080fd5b81356020615fcf615dcb83615f8b565b82815260059290921b84018101918181019086841115615fee57600080fd5b8286015b8481101561601257803561600581615f0b565b8352918301918301615ff2565b509695505050505050565b600082601f83011261602e57600080fd5b8135602061603e615dcb83615f8b565b82815260059290921b8401810191818101908684111561605d57600080fd5b8286015b848110156160125780358352918301918301616061565b600082601f83011261608957600080fd5b81356020616099615dcb83615f8b565b82815260059290921b840181019181810190868411156160b857600080fd5b8286015b848110156160125780356001600160401b038111156160db5760008081fd5b6160e98986838b0101615dac565b8452509183019183016160bc565b6000806000806080858703121561610d57600080fd5b84356001600160401b038082111561612457600080fd5b61613088838901615fae565b9550602087013591508082111561614657600080fd5b6161528883890161601d565b9450604087013591508082111561616857600080fd5b5061617587828801616078565b949793965093946060013593505050565b60006020828403121561619857600080fd5b813561204581615f0b565b600081518084526020808501945080840160005b838110156161dc5781516001600160a01b0316875295820195908201906001016161b7565b509495945050505050565b600081518084526020808501945080840160005b838110156161dc578151875295820195908201906001016161fb565b600081518084526020808501808196508360051b8101915082860160005b8581101561625f57828403895261624d848351615ecc565b98850198935090840190600101616235565b5091979650505050505050565b60808152600061627f60808301876161a3565b828103602084015261629181876161e7565b905082810360408401526162a58186616217565b905082810360608401526117468185616217565b600080600080600060a086880312156162d157600080fd5b853594506162e160208701615ce6565b93506162ef60408701615ce6565b94979396509394606081013594506080013592915050565b634e487b7160e01b600052602160045260246000fd5b602081016008831061633f57634e487b7160e01b600052602160045260246000fd5b91905290565b6000806040838503121561635857600080fd5b82359150602083013561636a81615f0b565b809150509250929050565b6000806040838503121561638857600080fd5b8235915061639860208401615ce6565b90509250929050565b6000806000806000608086880312156163b957600080fd5b853594506163c960208701615ce6565b935060408601356001600160401b03808211156163e557600080fd5b6163f189838a01615cf7565b9095509350606088013591508082111561640a57600080fd5b5061641788828901615dac565b9150509295509295909350565b6000806000806060858703121561643a57600080fd5b8435935061644a60208601615ce6565b925060408501356001600160401b0381111561646557600080fd5b61647187828801615cf7565b95989497509550505050565b6000806000806080858703121561649357600080fd5b84356001600160401b03808211156164aa57600080fd5b6164b688838901615fae565b955060208701359150808211156164cc57600080fd5b6164d88883890161601d565b945060408701359150808211156164ee57600080fd5b6164fa88838901616078565b9350606087013591508082111561651057600080fd5b50615f7f87828801615dac565b60ff60f81b8816815260e06020820152600061653c60e0830189615ecc565b828103604084015261654e8189615ecc565b606084018890526001600160a01b038716608085015260a0840186905283810360c0850152905061108981856161e7565b60008060006060848603121561659457600080fd5b833561659f81615f0b565b92506020840135915060408401356001600160401b038111156165c157600080fd5b6165cd86828701615dac565b9150509250925092565b600080600080604085870312156165ed57600080fd5b84356001600160401b038082111561660457600080fd5b61661088838901615cf7565b9096509450602087013591508082111561662957600080fd5b5061647187828801615cf7565b600080600080600060a0868803121561664e57600080fd5b853561665981615f0b565b9450602086013561666981615f0b565b935060408601356001600160401b038082111561668557600080fd5b61669189838a0161601d565b945060608801359150808211156166a757600080fd5b6166b389838a0161601d565b9350608088013591508082111561640a57600080fd5b600080600080606085870312156166df57600080fd5b84356166ea81615f0b565b93506020850135925060408501356001600160401b0381111561646557600080fd5b60006020828403121561671e57600080fd5b81356001600160401b038116811461204557600080fd5b600080600080600060a0868803121561674d57600080fd5b85356001600160401b038082111561676457600080fd5b61677089838a01615fae565b9650602088013591508082111561678657600080fd5b61679289838a0161601d565b955060408801359150808211156167a857600080fd5b6167b489838a01616078565b945060608801359150808211156167ca57600080fd5b6166b389838a01616078565b600080604083850312156167e957600080fd5b82356167f481615f0b565b946020939093013593505050565b600080600080600060a0868803121561681a57600080fd5b853561682581615f0b565b9450602086013561683581615f0b565b9350604086013592506060860135915060808601356001600160401b0381111561685e57600080fd5b61641788828901615dac565b8183823760009101908152919050565b60208082526018908201527f476f7665726e6f723a206f6e6c79476f7665726e616e63650000000000000000604082015260600190565b600181811c908216806168c557607f821691505b6020821081036168e557634e487b7160e01b600052602260045260246000fd5b50919050565b634e487b7160e01b600052603260045260246000fd5b634e487b7160e01b600052601160045260246000fd5b60006001820161692957616929616901565b5060010190565b65ffffffffffff82811682821603908082111561694f5761694f616901565b5092915050565b60208082526021908201527f476f7665726e6f723a2070726f706f73616c206e6f74207375636365737366756040820152601b60fa1b606082015260800190565b6000602082840312156169a957600080fd5b81516001600160401b038111156169bf57600080fd5b8201601f810184136169d057600080fd5b80516169de615dcb82615d85565b8181528560208385010111156169f357600080fd5b611327826020830160208601615ea8565b81810381811115610f9957610f99616901565b634e487b7160e01b600052601260045260246000fd5b600082616a4a57634e487b7160e01b600052601260045260246000fd5b500490565b600060208284031215616a6157600080fd5b815165ffffffffffff8116811461204557600080fd5b600060208284031215616a8957600080fd5b5051919050565b81835281816020850137506000828201602090810191909152601f909101601f19169091010190565b604081526000616acd604083018688616a90565b8281036020840152611746818587616a90565b608081526000616af360808301876161a3565b8281036020840152616b0581876161e7565b90508281036040840152616b198186616217565b91505082606083015295945050505050565b8082028115828204841417610f9957610f99616901565b60a081526000616b5560a08301886161a3565b8281036020840152616b6781886161e7565b90508281036040840152616b7b8187616217565b60608401959095525050608001529392505050565b60c081526000616ba360c08301896161a3565b8281036020840152616bb581896161e7565b90508281036040840152616bc98188616217565b60608401969096525050608081019290925260a0909101529392505050565b80820180821115610f9957610f99616901565b600060208284031215616c0d57600080fd5b8151801515811461204557600080fd5b6020808252602b908201527f496e697469616c697a61626c653a20636f6e7472616374206973206e6f74206960408201526a6e697469616c697a696e6760a81b606082015260800190565b60008251616c7a818460208701615ea8565b9190910192915050565b6001600160e01b0319831681528151600090616ca7816004850160208701615ea8565b919091016004019392505050565b6001600160401b0381811683821601908082111561694f5761694f616901565b60208082526021908201527f476f7665726e6f723a20696e76616c69642070726f706f73616c206c656e67746040820152600d60fb1b606082015260800190565b8981526001600160a01b038916602082015261012060408201819052600090616d418382018b6161a3565b90508281036060840152616d55818a6161e7565b90508281036080840152616d698189616217565b905082810360a0840152616d7d8188616217565b90508560c08401528460e0840152828103610100840152616d9e8185615ecc565b9c9b505050505050505050505050565b601f821115613be557600081815260208120601f850160051c81016020861015616dd55750805b601f850160051c820191505b8181101561177f57828155600101616de1565b81516001600160401b03811115616e0d57616e0d615d3f565b616e2181616e1b84546168b1565b84616dae565b602080601f831160018114616e565760008415616e3e5750858301515b600019600386901b1c1916600185901b17855561177f565b600085815260208120601f198616915b82811015616e8557888601518255948401946001909101908401616e66565b5085821015616ea35787850151600019600388901b60f8161c191681555b5050505050600190811b01905550565b84815260ff84166020820152826040820152608060608201526000611b366080830184615ecc565b85815260ff8516602082015283604082015260a060608201526000616f0360a0830185615ecc565b8281036080840152611c4f8185615ecc56fe476f7665726e6f723a2072656c617920726576657274656420776974686f7574206d657373616765a164736f6c6343000811000a \ No newline at end of file diff --git a/core/systemcontracts/pasteur/mainnet/StakeHubContract b/core/systemcontracts/pasteur/mainnet/StakeHubContract new file mode 100644 index 0000000000..23b1f5b576 --- /dev/null +++ b/core/systemcontracts/pasteur/mainnet/StakeHubContract @@ -0,0 +1 @@ +6080604052600436106200043b5760003560e01c806386d545061162000233578063ca47908f116200012f578063dd42a1dd11620000b9578063f1f74d841162000084578063f1f74d841462000d75578063f80a34021462000d8d578063fb50b31f1462000db2578063fc0c5ff11462000dd7578063ff69ab611462000def57600080fd5b8063dd42a1dd1462000ce2578063e8f67c3b1462000d09578063e992aaf51462000d21578063efdbf0e11462000d3957600080fd5b8063d7c2dfc811620000fa578063d7c2dfc81462000c68578063d8ca511f1462000c8d578063daacdb661462000ca5578063dbda7fb31462000cbd57600080fd5b8063ca47908f1462000bd1578063cbb04d9d1462000be9578063d115a2061462000c2a578063d6ca429d1462000c4357600080fd5b8063b187bd2611620001bd578063bfff04751162000188578063bfff04751462000b58578063c166f58a1462000b7d578063c38fbec81462000b94578063c473318f1462000bb9578063c8509d81146200095157600080fd5b8063b187bd261462000ac5578063baa7199e1462000ae5578063bdceadf31462000b0a578063bff02e201462000b2257600080fd5b8063a1832e6411620001fe578063a1832e641462000a22578063a43569b31462000a47578063aad3ec961462000a7b578063ac4317511462000aa057600080fd5b806386d54506146200098e5780638a4d3fa814620009c85780638cd22b2214620009e6578063982ef0a71462000a0b57600080fd5b80634838d165116200034357806364028fbd11620002cd57806375cc7d89116200029857806375cc7d8914620008fc57806376e7d6d614620009215780638129fc1c1462000939578063831d65d114620009515780638456cb59146200097657600080fd5b806364028fbd1462000837578063663706d3146200084e5780636ec01b27146200087f5780636f8e2fa414620008d757600080fd5b80634e6fd6c4116200030e5780634e6fd6c4146200079e5780635949187114620007b65780635e7cc1c914620007db57806363a036b5146200080057600080fd5b80634838d16514620006ea57806349f41a42146200072f5780634a49ac4c14620007545780634d99dd16146200077957600080fd5b80631fab701511620003c5578063384099881162000390578063384099881462000663578063417c73a7146200067b578063449ecfe614620006a057806345211bfd14620006c557600080fd5b80631fab701514620005aa5780632b727c8614620005cf5780632e8e8c7114620005f4578063367dad49146200062e57600080fd5b80630e9fbf5111620004065780630e9fbf5114620004f35780631182b875146200051857806317b4f353146200054c5780631fa8882b146200059157600080fd5b8063046f7da2146200045b578063059ddd2214620004735780630661806e14620004b5578063092193ab14620004dc57600080fd5b36620004565760345460ff166001146200045457600080fd5b005b600080fd5b3480156200046857600080fd5b506200045462000e07565b3480156200048057600080fd5b506200049862000492366004620097cc565b62000e99565b6040516001600160a01b0390911681526020015b60405180910390f35b348015620004c257600080fd5b50620004cd60365481565b604051908152602001620004ac565b62000454620004ed366004620097cc565b620012c1565b3480156200050057600080fd5b5062000454620005123660046200982e565b62001912565b3480156200052557600080fd5b506200053d6200053736600462009873565b62001c9e565b604051620004ac919062009926565b3480156200055957600080fd5b50620004986200056b366004620099f8565b80516020818301810180516045825292820191909301209152546001600160a01b031681565b3480156200059e57600080fd5b50620004cd6201518081565b348015620005b757600080fd5b5062000454620005c936600462009a94565b62001d36565b348015620005dc57600080fd5b5062000498620005ee366004620097cc565b6200208d565b3480156200060157600080fd5b506200049862000613366004620097cc565b604d602052600090815260409020546001600160a01b031681565b3480156200063b57600080fd5b50620006536200064d36600462009a94565b620020e2565b604051620004ac92919062009b13565b3480156200067057600080fd5b50620004cd60375481565b3480156200068857600080fd5b50620004546200069a366004620097cc565b620026b1565b348015620006ad57600080fd5b5062000454620006bf366004620097cc565b62002733565b348015620006d257600080fd5b5062000454620006e4366004620097cc565b62002918565b348015620006f757600080fd5b506200071e62000709366004620097cc565b60016020526000908152604090205460ff1681565b6040519015158152602001620004ac565b3480156200073c57600080fd5b50620004546200074e366004620097cc565b62002af1565b3480156200076157600080fd5b506200045462000773366004620097cc565b62002d0d565b3480156200078657600080fd5b50620004546200079836600462009bb2565b62002d89565b348015620007ab57600080fd5b506200049861dead81565b348015620007c357600080fd5b5062000454620007d536600462009bf0565b620033b9565b348015620007e857600080fd5b5062000454620007fa36600462009c5a565b620041b2565b3480156200080d57600080fd5b50620008256200081f36600462009c81565b620043dc565b604051620004ac949392919062009ca4565b620004546200084836600462009d60565b62004a81565b3480156200085b57600080fd5b50620004cd6200086d366004620097cc565b60446020526000908152604090205481565b3480156200088c57600080fd5b50620008a46200089e366004620097cc565b620050d0565b6040805182516001600160401b0390811682526020808501518216908301529282015190921690820152606001620004ac565b348015620008e457600080fd5b506200053d620008f6366004620097cc565b62005175565b3480156200090957600080fd5b50620004546200091b366004620097cc565b620055a1565b3480156200092e57600080fd5b50620004cd603d5481565b3480156200094657600080fd5b506200045462005773565b3480156200095e57600080fd5b50620004546200097036600462009873565b6200593e565b3480156200098357600080fd5b50620004546200599c565b3480156200099b57600080fd5b5062000498620009ad366004620097cc565b6043602052600090815260409020546001600160a01b031681565b348015620009d557600080fd5b50620004cd670de0b6b3a764000081565b348015620009f357600080fd5b50620004cd62000a0536600462009bb2565b62005a34565b6200045462000a1c36600462009e36565b62005aed565b34801562000a2f57600080fd5b506200045462000a4136600462009a94565b6200619b565b34801562000a5457600080fd5b5062000a6c62000a66366004620097cc565b620064a1565b604051620004ac919062009e6e565b34801562000a8857600080fd5b506200045462000a9a36600462009bb2565b6200678e565b34801562000aad57600080fd5b506200045462000abf36600462009eeb565b620067fb565b34801562000ad257600080fd5b5060005462010000900460ff166200071e565b34801562000af257600080fd5b506200045462000b0436600462009f5d565b620077ad565b34801562000b1757600080fd5b50620004cd603c5481565b34801562000b2f57600080fd5b5062000b4762000b4136600462009c81565b6200797a565b604051620004ac9392919062009fb6565b34801562000b6557600080fd5b50620004cd62000b77366004620097cc565b62007b56565b34801562000b8a57600080fd5b50620004cd600581565b34801562000ba157600080fd5b506200045462000bb3366004620097cc565b62007ba4565b34801562000bc657600080fd5b50620004cd60385481565b34801562000bde57600080fd5b50620004cd604e5481565b34801562000bf657600080fd5b5062000c0e62000c08366004620097cc565b62007ec6565b60408051938452911515602084015290820152606001620004ac565b34801562000c3757600080fd5b50620004cd620186a081565b34801562000c5057600080fd5b506200045462000c623660046200a013565b62008309565b34801562000c7557600080fd5b506200045462000c873660046200a0fc565b6200852f565b34801562000c9a57600080fd5b50620004cd603b5481565b34801562000cb257600080fd5b50620004cd60495481565b34801562000cca57600080fd5b506200049862000cdc366004620097cc565b62008625565b34801562000cef57600080fd5b50600054630100000090046001600160a01b031662000498565b34801562000d1657600080fd5b50620004cd60355481565b34801562000d2e57600080fd5b50620004cd603a5481565b34801562000d4657600080fd5b50620004cd62000d58366004620099f8565b805160208183018101805160468252928201919093012091525481565b34801562000d8257600080fd5b50620004cd603e5481565b34801562000d9a57600080fd5b50620004cd62000dac36600462009bb2565b62008a4f565b34801562000dbf57600080fd5b506200045462000dd136600462009eeb565b62008ac0565b34801562000de457600080fd5b50620004cd60395481565b34801562000dfc57600080fd5b50620004cd604a5481565b600054630100000090046001600160a01b0316331462000e3a576040516306fbb1e360e01b815260040160405180910390fd5b60005462010000900460ff1662000e6457604051636cd6020160e01b815260040160405180910390fd5b6000805462ff0000191681556040517f62451d457bc659158be6e6247f56ec1df424a5c7597f71c20c2bc44e0965c8f99190a1565b6001600160a01b038082166000908152604160209081526040808320815161018081018352815486168152600182015486169381019390935260028101549094169082015260038301546060820152600483018054929384939091608084019162000f04906200a162565b80601f016020809104026020016040519081016040528092919081815260200182805462000f32906200a162565b801562000f835780601f1062000f575761010080835404028352916020019162000f83565b820191906000526020600020905b81548152906001019060200180831162000f6557829003601f168201915b505050505081526020016005820160405180608001604052908160008201805462000fae906200a162565b80601f016020809104026020016040519081016040528092919081815260200182805462000fdc906200a162565b80156200102d5780601f1062001001576101008083540402835291602001916200102d565b820191906000526020600020905b8154815290600101906020018083116200100f57829003601f168201915b5050505050815260200160018201805462001048906200a162565b80601f016020809104026020016040519081016040528092919081815260200182805462001076906200a162565b8015620010c75780601f106200109b57610100808354040283529160200191620010c7565b820191906000526020600020905b815481529060010190602001808311620010a957829003601f168201915b50505050508152602001600282018054620010e2906200a162565b80601f016020809104026020016040519081016040528092919081815260200182805462001110906200a162565b8015620011615780601f10620011355761010080835404028352916020019162001161565b820191906000526020600020905b8154815290600101906020018083116200114357829003601f168201915b505050505081526020016003820180546200117c906200a162565b80601f0160208091040260200160405190810160405280929190818152602001828054620011aa906200a162565b8015620011fb5780601f10620011cf57610100808354040283529160200191620011fb565b820191906000526020600020905b815481529060010190602001808311620011dd57829003601f168201915b505050919092525050508152604080516060808201835260098501546001600160401b038082168452600160401b82048116602080860191909152600160801b9092041683850152840191909152600a84015460ff16151582840152600b84015490830152600c8301546080830152600d8301546001600160a01b031660a0830152805161026081019182905260c09092019190600e84019060139082845b8154815260200190600101908083116200129a575050509190925250509051949350505050565b3361100014620012ed57604051630f22c43960e41b815261100060048201526024015b60405180910390fd5b6001600160a01b0380821660009081526043602090815260408083205484168084526041835281842082516101808101845281548716815260018201548716948101949094526002810154909516918301919091526003840154606083015260048401805491949160808401919062001366906200a162565b80601f016020809104026020016040519081016040528092919081815260200182805462001394906200a162565b8015620013e55780601f10620013b957610100808354040283529160200191620013e5565b820191906000526020600020905b815481529060010190602001808311620013c757829003601f168201915b505050505081526020016005820160405180608001604052908160008201805462001410906200a162565b80601f01602080910402602001604051908101604052809291908181526020018280546200143e906200a162565b80156200148f5780601f1062001463576101008083540402835291602001916200148f565b820191906000526020600020905b8154815290600101906020018083116200147157829003601f168201915b50505050508152602001600182018054620014aa906200a162565b80601f0160208091040260200160405190810160405280929190818152602001828054620014d8906200a162565b8015620015295780601f10620014fd5761010080835404028352916020019162001529565b820191906000526020600020905b8154815290600101906020018083116200150b57829003601f168201915b5050505050815260200160028201805462001544906200a162565b80601f016020809104026020016040519081016040528092919081815260200182805462001572906200a162565b8015620015c35780601f106200159757610100808354040283529160200191620015c3565b820191906000526020600020905b815481529060010190602001808311620015a557829003601f168201915b50505050508152602001600382018054620015de906200a162565b80601f01602080910402602001604051908101604052809291908181526020018280546200160c906200a162565b80156200165d5780601f1062001631576101008083540402835291602001916200165d565b820191906000526020600020905b8154815290600101906020018083116200163f57829003601f168201915b505050919092525050508152604080516060808201835260098501546001600160401b038082168452600160401b82048116602080860191909152600160801b9092041683850152840191909152600a84015460ff16151582840152600b84015490830152600c8301546080830152600d8301546001600160a01b031660a0830152805161026081019182905260c09092019190600e84019060139082845b815481526020019060010190808311620016fc575050509190925250505060408101519091506001600160a01b031615806200173957508060e001515b15620017f657604051611002903490600081818185875af1925050503d806000811462001783576040519150601f19603f3d011682016040523d82523d6000602084013e62001788565b606091505b505050816001600160a01b03167ffc8bff675087dd2da069cc3fb517b9ed001e19750c0865241a5542dba1ba170d604051620017e99060208082526011908201527024a72b20a624a22fab20a624a220aa27a960791b604082015260600190565b60405180910390a2505050565b60408181015160c0830151519151632f303ebb60e11b81526001600160401b0390921660048301526001600160a01b031690635e607d769034906024016000604051808303818588803b1580156200184d57600080fd5b505af115801562001862573d6000803e3d6000fd5b5050505050816001600160a01b03167fe34918ff1c7084970068b53fd71ad6d8b04e9f15d3886cbf006443e6cdc52ea634604051620018a391815260200190565b60405180910390a26040808201519051633041949b60e01b815261200591633041949b91620018d8919086906004016200a198565b600060405180830381600087803b158015620018f357600080fd5b505af115801562001908573d6000803e3d6000fd5b5050505050505b50565b33611001146200193a57604051630f22c43960e41b81526110016004820152602401620012e4565b60005462010000900460ff16156200196557604051631785c68160e01b815260040160405180910390fd5b6000604583836040516200197b9291906200a1b2565b908152604051908190036020019020546001600160a01b03169050620019a3603f8262008cf9565b620019c15760405163056e881160e01b815260040160405180910390fd5b6001600160a01b038116600090815260416020526040812090620019e962015180426200a1d8565b604a546000828152604b60205260409020549192501162001a1d5760405163bd52fcdb60e01b815260040160405180910390fd5b6000818152604b6020526040812080546001929062001a3e9084906200a1fb565b909155505060405160469062001a5890879087906200a1b2565b90815260200160405180910390205460001415801562001aa9575042620151806046878760405162001a8c9291906200a1b2565b90815260200160405180910390205462001aa791906200a1fb565b105b1562001ac857604051631898eb6b60e01b815260040160405180910390fd5b60008062001ad885600262008d1c565b915091508162001afb57604051631b919bb160e11b815260040160405180910390fd5b6002840154603c5460405163045bc4d160e41b815260048101919091526000916001600160a01b0316906345bc4d10906024016020604051808303816000875af115801562001b4e573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019062001b7491906200a211565b905062001b82858362008da4565b84546040516335409f7f60e01b81526001600160a01b039091166004820152611000906335409f7f90602401600060405180830381600087803b15801562001bc957600080fd5b505af115801562001bde573d6000803e3d6000fd5b50505050856001600160a01b03167f6e9a2ee7aee95665e3a774a212eb11441b217e3e4656ab9563793094689aabb28383600260405162001c22939291906200a22b565b60405180910390a26002850154604051633041949b60e01b815261200591633041949b9162001c60916001600160a01b0316908a906004016200a198565b600060405180830381600087803b15801562001c7b57600080fd5b505af115801562001c90573d6000803e3d6000fd5b505050505050505050505050565b6060336120001462001cc857604051630f22c43960e41b81526120006004820152602401620012e4565b60005462010000900460ff161562001cf357604051631785c68160e01b815260040160405180910390fd5b6034805460ff1916600117905560405162461bcd60e51b815260206004820152600a60248201526919195c1c9958d85d195960b21b6044820152606401620012e4565b60005462010000900460ff161562001d6157604051631785c68160e01b815260040160405180910390fd5b3360009081526001602052604090205460ff161562001d935760405163b1d02c3d60e01b815260040160405180910390fd5b62001d9d62008e98565b62001daa603f8262008cf9565b62001dc85760405163056e881160e01b815260040160405180910390fd5b62001dd262008eff565b600082900362001df557604051636490ffd360e01b815260040160405180910390fd5b600062001e0162008e98565b6001600160a01b0381166000908152604f602052604090208054604e54929350909162001e2f86836200a1fb565b111562001e4f5760405163091af98560e21b815260040160405180910390fd5b60005b8581101562001f3557600087878381811062001e725762001e726200a266565b905060200201350362001e9857604051636490ffd360e01b815260040160405180910390fd5b600062001ea78260016200a1fb565b90505b8681101562001f1f5787878281811062001ec85762001ec86200a266565b9050602002013588888481811062001ee45762001ee46200a266565b905060200201350362001f0a57604051632205e3c760e11b815260040160405180910390fd5b8062001f16816200a27c565b91505062001eaa565b508062001f2c816200a27c565b91505062001e52565b5060005b8581101562001fd45760005b8281101562001fbe5783818154811062001f635762001f636200a266565b906000526020600020015488888481811062001f835762001f836200a266565b905060200201350362001fa957604051632205e3c760e11b815260040160405180910390fd5b8062001fb5816200a27c565b91505062001f45565b508062001fcb816200a27c565b91505062001f39565b5060005b8581101562001908578287878381811062001ff75762001ff76200a266565b835460018101855560009485526020948590209190940292909201359190920155506001600160a01b0384167f7c4ff4c9a343a2daef608f3b5a91016e994a15fc0ef8611109e4f45823249f298888848181106200205957620020596200a266565b905060200201356040516200207091815260200190565b60405180910390a28062002084816200a27c565b91505062001fd8565b6000816200209d603f8262008cf9565b620020bb5760405163056e881160e01b815260040160405180910390fd5b6001600160a01b038084166000908152604160205260409020600d01541691505b50919050565b60608082806001600160401b038111156200210157620021016200993b565b6040519080825280602002602001820160405280156200212b578160200160208202803683370190505b509250806001600160401b038111156200214957620021496200993b565b6040519080825280602002602001820160405280156200217e57816020015b6060815260200190600190039081620021685790505b50915060005b81811015620026a7576000868683818110620021a457620021a46200a266565b9050602002016020810190620021bb9190620097cc565b6001600160a01b0380821660009081526041602090815260408083208151610180810183528154861681526001820154861693810193909352600281015490941690820152600383015460608201526004830180549495509193909291608084019162002228906200a162565b80601f016020809104026020016040519081016040528092919081815260200182805462002256906200a162565b8015620022a75780601f106200227b57610100808354040283529160200191620022a7565b820191906000526020600020905b8154815290600101906020018083116200228957829003601f168201915b5050505050815260200160058201604051806080016040529081600082018054620022d2906200a162565b80601f016020809104026020016040519081016040528092919081815260200182805462002300906200a162565b8015620023515780601f10620023255761010080835404028352916020019162002351565b820191906000526020600020905b8154815290600101906020018083116200233357829003601f168201915b505050505081526020016001820180546200236c906200a162565b80601f01602080910402602001604051908101604052809291908181526020018280546200239a906200a162565b8015620023eb5780601f10620023bf57610100808354040283529160200191620023eb565b820191906000526020600020905b815481529060010190602001808311620023cd57829003601f168201915b5050505050815260200160028201805462002406906200a162565b80601f016020809104026020016040519081016040528092919081815260200182805462002434906200a162565b8015620024855780601f10620024595761010080835404028352916020019162002485565b820191906000526020600020905b8154815290600101906020018083116200246757829003601f168201915b50505050508152602001600382018054620024a0906200a162565b80601f0160208091040260200160405190810160405280929190818152602001828054620024ce906200a162565b80156200251f5780601f10620024f3576101008083540402835291602001916200251f565b820191906000526020600020905b8154815290600101906020018083116200250157829003601f168201915b505050919092525050508152604080516060808201835260098501546001600160401b038082168452600160401b82048116602080860191909152600160801b9092041683850152840191909152600a84015460ff16151582840152600b84015490830152600c8301546080830152600d8301546001600160a01b031660a0830152805161026081019182905260c09092019190600e84019060139082845b815481526020019060010190808311620025be5750505050508152505090508060000151868481518110620025f757620025f76200a266565b6001600160a01b039283166020918202929092018101919091529083166000908152604f8252604090819020805482518185028101850190935280835291929091908301828280156200266a57602002820191906000526020600020905b81548152602001906001019080831162002655575b50505050508584815181106200268457620026846200a266565b6020026020010181905250505080806200269e906200a27c565b91505062002184565b50505b9250929050565b600054630100000090046001600160a01b03163314620026e4576040516306fbb1e360e01b815260040160405180910390fd5b6001600160a01b0381166000818152600160208190526040808320805460ff1916909217909155517f7fd26be6fc92aff63f1f4409b2b2ddeb272a888031d7f55ec830485ec61941869190a250565b60005462010000900460ff16156200275e57604051631785c68160e01b815260040160405180910390fd5b3360009081526001602052604090205460ff1615620027905760405163b1d02c3d60e01b815260040160405180910390fd5b806200279e603f8262008cf9565b620027bc5760405163056e881160e01b815260040160405180910390fd5b6001600160a01b0382166000908152604160205260409020600a81015460ff16620027fa57604051634b6b857d60e01b815260040160405180910390fd5b6036546002820154604051630913db4760e01b81526001600160a01b03868116600483015290911690630913db4790602401602060405180830381865afa1580156200284a573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906200287091906200a211565b101562002890576040516317b204bf60e11b815260040160405180910390fd5b4281600b01541115620028b65760405163170cb76760e21b815260040160405180910390fd5b600a8101805460ff191690556049805460019190600090620028da9084906200a298565b90915550506040516001600160a01b038416907f9390b453426557da5ebdc31f19a37753ca04addf656d32f35232211bb2af3f1990600090a2505050565b60005462010000900460ff16156200294357604051631785c68160e01b815260040160405180910390fd5b3360009081526001602052604090205460ff1615620029755760405163b1d02c3d60e01b815260040160405180910390fd5b6200297f62008f12565b6200298c603f8262008cf9565b620029aa5760405163056e881160e01b815260040160405180910390fd5b6001600160a01b038216620029d257604051636520611b60e11b815260040160405180910390fd5b6001600160a01b03828116600090815260436020526040902054161562002a0c57604051631e6f587560e11b815260040160405180910390fd5b600062002a1862008f12565b6001600160a01b0381166000908152604160205260409020600c81015491925090429062002a4b9062015180906200a1fb565b111562002a6b57604051631f92cdbd60e11b815260040160405180910390fd5b80546001600160a01b039081166000908152604460209081526040808320429081905585548986166001600160a01b031991821681178855600c88019290925581855260439093528184208054958816959093168517909255519092917f6e4e747ca35203f16401c69805c7dd52fff67ef60b0ebc5c7fe16890530f223591a350505050565b3362002aff603f8262008cf9565b62002b1d5760405163056e881160e01b815260040160405180910390fd5b60005462010000900460ff161562002b4857604051631785c68160e01b815260040160405180910390fd5b3360009081526001602052604090205460ff161562002b7a5760405163b1d02c3d60e01b815260040160405180910390fd5b6001600160a01b038281166000908152604d6020526040902054161562002bb45760405163bebdc75760e01b815260040160405180910390fd5b62002bc1603f8362008cf9565b1562002be05760405163bebdc75760e01b815260040160405180910390fd5b336000818152604160205260409020600d01546001600160a01b03908116908416810362002c215760405163bebdc75760e01b815260040160405180910390fd5b6001600160a01b0381161562002c58576001600160a01b0381166000908152604d6020526040902080546001600160a01b03191690555b6001600160a01b038281166000908152604160205260409020600d0180546001600160a01b03191691861691821790551562002cbd576001600160a01b038481166000908152604d6020526040902080546001600160a01b0319169184169190911790555b836001600160a01b0316816001600160a01b0316836001600160a01b03167fcbb728765de145e99c00e8ae32a325231e850359b7b8a6da3b84d672ab3f1d0a60405160405180910390a450505050565b600054630100000090046001600160a01b0316331462002d40576040516306fbb1e360e01b815260040160405180910390fd5b6001600160a01b038116600081815260016020526040808220805460ff19169055517fe0db3499b7fdc3da4cddff5f45d694549c19835e7f719fb5606d3ad1a5de40119190a250565b60005462010000900460ff161562002db457604051631785c68160e01b815260040160405180910390fd5b3360009081526001602052604090205460ff161562002de65760405163b1d02c3d60e01b815260040160405180910390fd5b8162002df4603f8262008cf9565b62002e125760405163056e881160e01b815260040160405180910390fd5b8160000362002e3457604051639811e0c760e01b815260040160405180910390fd5b6001600160a01b038084166000908152604160209081526040808320815161018081018352815486168152600182015486169381019390935260028101549094169082015260038301546060820152600483018054339491608084019162002e9c906200a162565b80601f016020809104026020016040519081016040528092919081815260200182805462002eca906200a162565b801562002f1b5780601f1062002eef5761010080835404028352916020019162002f1b565b820191906000526020600020905b81548152906001019060200180831162002efd57829003601f168201915b505050505081526020016005820160405180608001604052908160008201805462002f46906200a162565b80601f016020809104026020016040519081016040528092919081815260200182805462002f74906200a162565b801562002fc55780601f1062002f995761010080835404028352916020019162002fc5565b820191906000526020600020905b81548152906001019060200180831162002fa757829003601f168201915b5050505050815260200160018201805462002fe0906200a162565b80601f01602080910402602001604051908101604052809291908181526020018280546200300e906200a162565b80156200305f5780601f1062003033576101008083540402835291602001916200305f565b820191906000526020600020905b8154815290600101906020018083116200304157829003601f168201915b505050505081526020016002820180546200307a906200a162565b80601f0160208091040260200160405190810160405280929190818152602001828054620030a8906200a162565b8015620030f95780601f10620030cd57610100808354040283529160200191620030f9565b820191906000526020600020905b815481529060010190602001808311620030db57829003601f168201915b5050505050815260200160038201805462003114906200a162565b80601f016020809104026020016040519081016040528092919081815260200182805462003142906200a162565b8015620031935780601f10620031675761010080835404028352916020019162003193565b820191906000526020600020905b8154815290600101906020018083116200317557829003601f168201915b505050919092525050508152604080516060808201835260098501546001600160401b038082168452600160401b82048116602080860191909152600160801b9092041683850152840191909152600a84015460ff16151582840152600b84015490830152600c8301546080830152600d8301546001600160a01b031660a0830152805161026081019182905260c09092019190600e84019060139082845b81548152602001906001019080831162003232575050509190925250505060408082015190516326ccee8b60e11b81526001600160a01b0385811660048301526024820188905292935060009290911690634d99dd16906044016020604051808303816000875af1158015620032ac573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190620032d291906200a211565b9050826001600160a01b0316866001600160a01b03167f3aace7340547de7b9156593a7652dc07ee900cea3fd8f82cb6c9d38b40829802878460405162003323929190918252602082015260400190565b60405180910390a3856001600160a01b0316836001600160a01b0316036200335057620033508662008f53565b6040808301519051633041949b60e01b815261200591633041949b916200337d919087906004016200a198565b600060405180830381600087803b1580156200339857600080fd5b505af1158015620033ad573d6000803e3d6000fd5b50505050505050505050565b60005462010000900460ff1615620033e457604051631785c68160e01b815260040160405180910390fd5b3360009081526001602052604090205460ff1615620034165760405163b1d02c3d60e01b815260040160405180910390fd5b8362003424603f8262008cf9565b620034425760405163056e881160e01b815260040160405180910390fd5b8362003450603f8262008cf9565b6200346e5760405163056e881160e01b815260040160405180910390fd5b6034805460ff1916600117905560008490036200349e57604051639811e0c760e01b815260040160405180910390fd5b846001600160a01b0316866001600160a01b031603620034d15760405163f0e3e62960e01b815260040160405180910390fd5b6001600160a01b038087166000908152604160209081526040808320815161018081018352815486168152600182015486169381019390935260028101549094169082015260038301546060820152600483018054339491608084019162003539906200a162565b80601f016020809104026020016040519081016040528092919081815260200182805462003567906200a162565b8015620035b85780601f106200358c57610100808354040283529160200191620035b8565b820191906000526020600020905b8154815290600101906020018083116200359a57829003601f168201915b5050505050815260200160058201604051806080016040529081600082018054620035e3906200a162565b80601f016020809104026020016040519081016040528092919081815260200182805462003611906200a162565b8015620036625780601f10620036365761010080835404028352916020019162003662565b820191906000526020600020905b8154815290600101906020018083116200364457829003601f168201915b505050505081526020016001820180546200367d906200a162565b80601f0160208091040260200160405190810160405280929190818152602001828054620036ab906200a162565b8015620036fc5780601f10620036d057610100808354040283529160200191620036fc565b820191906000526020600020905b815481529060010190602001808311620036de57829003601f168201915b5050505050815260200160028201805462003717906200a162565b80601f016020809104026020016040519081016040528092919081815260200182805462003745906200a162565b8015620037965780601f106200376a5761010080835404028352916020019162003796565b820191906000526020600020905b8154815290600101906020018083116200377857829003601f168201915b50505050508152602001600382018054620037b1906200a162565b80601f0160208091040260200160405190810160405280929190818152602001828054620037df906200a162565b8015620038305780601f10620038045761010080835404028352916020019162003830565b820191906000526020600020905b8154815290600101906020018083116200381257829003601f168201915b505050919092525050508152604080516060808201835260098501546001600160401b038082168452600160401b82048116602080860191909152600160801b9092041683850152840191909152600a84015460ff16151582840152600b84015490830152600c8301546080830152600d8301546001600160a01b031660a0830152805161026081019182905260c09092019190600e84019060139082845b815481526020019060010190808311620038cf57505050919092525050506001600160a01b038089166000908152604160209081526040808320815161018081018352815486168152600182015486169381019390935260028101549094169082015260038301546060820152600483018054949550919390929160808401916200395a906200a162565b80601f016020809104026020016040519081016040528092919081815260200182805462003988906200a162565b8015620039d95780601f10620039ad57610100808354040283529160200191620039d9565b820191906000526020600020905b815481529060010190602001808311620039bb57829003601f168201915b505050505081526020016005820160405180608001604052908160008201805462003a04906200a162565b80601f016020809104026020016040519081016040528092919081815260200182805462003a32906200a162565b801562003a835780601f1062003a575761010080835404028352916020019162003a83565b820191906000526020600020905b81548152906001019060200180831162003a6557829003601f168201915b5050505050815260200160018201805462003a9e906200a162565b80601f016020809104026020016040519081016040528092919081815260200182805462003acc906200a162565b801562003b1d5780601f1062003af15761010080835404028352916020019162003b1d565b820191906000526020600020905b81548152906001019060200180831162003aff57829003601f168201915b5050505050815260200160028201805462003b38906200a162565b80601f016020809104026020016040519081016040528092919081815260200182805462003b66906200a162565b801562003bb75780601f1062003b8b5761010080835404028352916020019162003bb7565b820191906000526020600020905b81548152906001019060200180831162003b9957829003601f168201915b5050505050815260200160038201805462003bd2906200a162565b80601f016020809104026020016040519081016040528092919081815260200182805462003c00906200a162565b801562003c515780601f1062003c255761010080835404028352916020019162003c51565b820191906000526020600020905b81548152906001019060200180831162003c3357829003601f168201915b505050919092525050508152604080516060808201835260098501546001600160401b038082168452600160401b82048116602080860191909152600160801b9092041683850152840191909152600a84015460ff16151582840152600b84015490830152600c8301546080830152600d8301546001600160a01b031660a0830152805161026081019182905260c09092019190600e84019060139082845b81548152602001906001019080831162003cf05750505050508152505090508060e00151801562003d335750876001600160a01b0316836001600160a01b031614155b1562003d5257604051636468920360e01b815260040160405180910390fd5b60408083015190516352e82ce560e11b81526001600160a01b038581166004830152602482018a9052600092169063a5d059ca906044016020604051808303816000875af115801562003da9573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019062003dcf91906200a211565b905060375481101562003df55760405163dc6f0bdd60e01b815260040160405180910390fd5b896001600160a01b0316846001600160a01b031614801562003e8a57506036546040808501519051630913db4760e01b81526001600160a01b038d8116600483015290911690630913db4790602401602060405180830381865afa15801562003e62573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019062003e8891906200a211565b105b1562003ea9576040516317b204bf60e11b815260040160405180910390fd5b6000620186a0603a548362003ebf91906200a2ae565b62003ecb91906200a1d8565b9050600083604001516001600160a01b03168260405160006040518083038185875af1925050503d806000811462003f20576040519150601f19603f3d011682016040523d82523d6000602084013e62003f25565b606091505b505090508062003f48576040516312171d8360e31b815260040160405180910390fd5b62003f5482846200a298565b60408086015190516317066a5760e21b81526001600160a01b03898116600483015292955060009290911690635c19a95c90869060240160206040518083038185885af115801562003faa573d6000803e3d6000fd5b50505050506040513d601f19601f8201168201806040525081019062003fd191906200a211565b9050866001600160a01b03168c6001600160a01b03168e6001600160a01b03167ffdac6e81913996d95abcc289e90f2d8bd235487ce6fe6f821e7d21002a1915b48e858960405162004036939291909283526020830191909152604082015260600190565b60405180910390a46040805160028082526060820183526000926020830190803683370190505090508660400151816000815181106200407a576200407a6200a266565b60200260200101906001600160a01b031690816001600160a01b031681525050856040015181600181518110620040b557620040b56200a266565b6001600160a01b0390921660209283029190910190910152604051634484077560e01b815261200590634484077590620040f69084908c906004016200a2c8565b600060405180830381600087803b1580156200411157600080fd5b505af115801562004126573d6000803e3d6000fd5b505050508a1562004198576120056001600160a01b031663e5ed5b1e898f6040518363ffffffff1660e01b8152600401620041639291906200a198565b600060405180830381600087803b1580156200417e57600080fd5b505af115801562004193573d6000803e3d6000fd5b505050505b50506034805460ff19169055505050505050505050505050565b60005462010000900460ff1615620041dd57604051631785c68160e01b815260040160405180910390fd5b3360009081526001602052604090205460ff16156200420f5760405163b1d02c3d60e01b815260040160405180910390fd5b6200421962008f12565b62004226603f8262008cf9565b620042445760405163056e881160e01b815260040160405180910390fd5b60006200425062008f12565b6001600160a01b0381166000908152604160205260409020600c810154919250904290620042839062015180906200a1fb565b1115620042a357604051631f92cdbd60e11b815260040160405180910390fd5b60098101546001600160401b03600160401b90910481169085161115620042dd5760405163dc81db8560e01b815260040160405180910390fd5b60098101546000906001600160401b0390811690861610156200431b576009820154620043159086906001600160401b03166200a2f4565b62004335565b600982015462004335906001600160401b0316866200a2f4565b60098301546001600160401b039182169250600160801b900416811115620043705760405163dc81db8560e01b815260040160405180910390fd5b60098201805467ffffffffffffffff19166001600160401b03871690811790915542600c8401556040519081526001600160a01b038416907f78cdd96edf59e09cfd4d26ef6ef6c92d166effe6a40970c54821206d541932cb9060200160405180910390a25050505050565b60608060606000620043ef603f62009071565b90508086101562004a785784156200440857846200440a565b805b94506000856200441b88846200a298565b1162004433576200442d87836200a298565b62004435565b855b9050806001600160401b038111156200445257620044526200993b565b6040519080825280602002602001820160405280156200447c578160200160208202803683370190505b509450806001600160401b038111156200449a576200449a6200993b565b604051908082528060200260200182016040528015620044c4578160200160208202803683370190505b509350806001600160401b03811115620044e257620044e26200993b565b6040519080825280602002602001820160405280156200451757816020015b6060815260200190600190039081620045015790505b50925060005b8181101562004a755760006200454162004538838b6200a1fb565b603f906200907c565b6001600160a01b03808216600090815260416020908152604080832081516101808101835281548616815260018201548616938101939093526002810154909416908201526003830154606082015260048301805494955091939092916080840191620045ae906200a162565b80601f0160208091040260200160405190810160405280929190818152602001828054620045dc906200a162565b80156200462d5780601f1062004601576101008083540402835291602001916200462d565b820191906000526020600020905b8154815290600101906020018083116200460f57829003601f168201915b505050505081526020016005820160405180608001604052908160008201805462004658906200a162565b80601f016020809104026020016040519081016040528092919081815260200182805462004686906200a162565b8015620046d75780601f10620046ab57610100808354040283529160200191620046d7565b820191906000526020600020905b815481529060010190602001808311620046b957829003601f168201915b50505050508152602001600182018054620046f2906200a162565b80601f016020809104026020016040519081016040528092919081815260200182805462004720906200a162565b8015620047715780601f10620047455761010080835404028352916020019162004771565b820191906000526020600020905b8154815290600101906020018083116200475357829003601f168201915b505050505081526020016002820180546200478c906200a162565b80601f0160208091040260200160405190810160405280929190818152602001828054620047ba906200a162565b80156200480b5780601f10620047df576101008083540402835291602001916200480b565b820191906000526020600020905b815481529060010190602001808311620047ed57829003601f168201915b5050505050815260200160038201805462004826906200a162565b80601f016020809104026020016040519081016040528092919081815260200182805462004854906200a162565b8015620048a55780601f106200487957610100808354040283529160200191620048a5565b820191906000526020600020905b8154815290600101906020018083116200488757829003601f168201915b505050919092525050508152604080516060808201835260098501546001600160401b038082168452600160401b82048116602080860191909152600160801b9092041683850152840191909152600a84015460ff16151582840152600b84015490830152600c8301546080830152600d8301546001600160a01b031660a0830152805161026081019182905260c09092019190600e84019060139082845b8154815260200190600101908083116200494457505050505081525050905080600001518884815181106200497d576200497d6200a266565b60200260200101906001600160a01b031690816001600160a01b0316815250508060e0015162004a165780604001516001600160a01b03166315d1f8986040518163ffffffff1660e01b8152600401602060405180830381865afa158015620049ea573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019062004a1091906200a211565b62004a19565b60005b87848151811062004a2e5762004a2e6200a266565b602002602001018181525050806080015186848151811062004a545762004a546200a266565b602002602001018190525050508062004a6d906200a27c565b90506200451d565b50505b92959194509250565b60005462010000900460ff161562004aac57604051631785c68160e01b815260040160405180910390fd5b3360009081526001602052604090205460ff161562004ade5760405163b1d02c3d60e01b815260040160405180910390fd5b3362004aec603f8262008cf9565b1562004b0b57604051635f28f62b60e01b815260040160405180910390fd5b6001600160a01b038181166000908152604d6020526040902054161562004b4557604051631a0a9b9f60e21b815260040160405180910390fd5b6001600160a01b03888116600090815260436020526040902054161562004b7f57604051631e6f587560e11b815260040160405180910390fd5b60006001600160a01b03166045888860405162004b9e9291906200a1b2565b908152604051908190036020019020546001600160a01b03161462004bd6576040516311fdb94760e01b815260040160405180910390fd5b600062004be483806200a31e565b60405160200162004bf79291906200a1b2565b60408051601f1981840301815291815281516020928301206000818152604290935291205490915060ff161562004c415760405163c0bf414360e01b815260040160405180910390fd5b600062004c57670de0b6b3a7640000346200a298565b905060365481101562004c7d576040516317b204bf60e11b815260040160405180910390fd5b6001600160a01b038a1662004ca557604051636520611b60e11b815260040160405180910390fd5b61138862004cba604087016020880162009c5a565b6001600160401b0316118062004d00575062004cdd604086016020870162009c5a565b6001600160401b031662004cf5602087018762009c5a565b6001600160401b0316115b8062004d3f575062004d19604086016020870162009c5a565b6001600160401b031662004d34606087016040880162009c5a565b6001600160401b0316115b1562004d5e5760405163dc81db8560e01b815260040160405180910390fd5b62004da962004d6e85806200a31e565b8080601f0160208091040260200160405190810160405280939291908181526020018383808284376000920191909152506200908a92505050565b62004dc757604051635dba5ad760e01b815260040160405180910390fd5b62004dd6838a8a8a8a6200922c565b62004df457604051631647e3cb60e11b815260040160405180910390fd5b600062004e428462004e0787806200a31e565b8080601f0160208091040260200160405190810160405280939291908181526020018383808284376000920191909152506200935c92505050565b905062004e51603f856200945d565b506000838152604260209081526040808320805460ff191660019081179091556001600160a01b0380891680865260419094529190932080548f83166001600160a01b03199182161782559381018054851690931790925560028201805491851691909316179091554260038201556004810162004ed18b8d836200a3c6565b50856005820162004ee382826200a48e565b508790506009820162004ef782826200a5c7565b505042600c8201556001600160a01b038c81166000908152604360205260409081902080546001600160a01b0319169288169290921790915551859060459062004f45908e908e906200a1b2565b908152602001604051809103902060006101000a8154816001600160a01b0302191690836001600160a01b03160217905550816001600160a01b0316856001600160a01b03168d6001600160a01b03167faecd9fb95e79c75a3a1de93362c6be5fe6ab65770d8614be583884161cd8228d8e8e60405162004fc89291906200a697565b60405180910390a460408051848152602081018590526001600160a01b0387169182917f24d7bda8602b916d64417f0dbfe2e2e88ec9b1157bd9f596dfdb91ba26624e04910160405180910390a360408051670de0b6b3a7640000808252602082015261dead916001600160a01b038816917f24d7bda8602b916d64417f0dbfe2e2e88ec9b1157bd9f596dfdb91ba26624e04910160405180910390a3604051633041949b60e01b815261200590633041949b906200508e90859089906004016200a198565b600060405180830381600087803b158015620050a957600080fd5b505af1158015620050be573d6000803e3d6000fd5b50505050505050505050505050505050565b604080516060810182526000808252602082018190529181019190915281620050fb603f8262008cf9565b620051195760405163056e881160e01b815260040160405180910390fd5b50506001600160a01b031660009081526041602090815260409182902082516060810184526009909101546001600160401b038082168352600160401b8204811693830193909352600160801b90049091169181019190915290565b6001600160a01b03808216600090815260416020908152604080832081516101808101835281548616815260018201548616938101939093526002810154909416908201526003830154606082810191909152600484018054919491608084019190620051e2906200a162565b80601f016020809104026020016040519081016040528092919081815260200182805462005210906200a162565b8015620052615780601f10620052355761010080835404028352916020019162005261565b820191906000526020600020905b8154815290600101906020018083116200524357829003601f168201915b50505050508152602001600582016040518060800160405290816000820180546200528c906200a162565b80601f0160208091040260200160405190810160405280929190818152602001828054620052ba906200a162565b80156200530b5780601f10620052df576101008083540402835291602001916200530b565b820191906000526020600020905b815481529060010190602001808311620052ed57829003601f168201915b5050505050815260200160018201805462005326906200a162565b80601f016020809104026020016040519081016040528092919081815260200182805462005354906200a162565b8015620053a55780601f106200537957610100808354040283529160200191620053a5565b820191906000526020600020905b8154815290600101906020018083116200538757829003601f168201915b50505050508152602001600282018054620053c0906200a162565b80601f0160208091040260200160405190810160405280929190818152602001828054620053ee906200a162565b80156200543f5780601f1062005413576101008083540402835291602001916200543f565b820191906000526020600020905b8154815290600101906020018083116200542157829003601f168201915b505050505081526020016003820180546200545a906200a162565b80601f016020809104026020016040519081016040528092919081815260200182805462005488906200a162565b8015620054d95780601f10620054ad57610100808354040283529160200191620054d9565b820191906000526020600020905b815481529060010190602001808311620054bb57829003601f168201915b505050919092525050508152604080516060808201835260098501546001600160401b038082168452600160401b82048116602080860191909152600160801b9092041683850152840191909152600a84015460ff16151582840152600b84015490830152600c8301546080830152600d8301546001600160a01b031660a0830152805161026081019182905260c09092019190600e84019060139082845b815481526020019060010190808311620055785750505091909252505050608001519392505050565b3361100114620055c957604051630f22c43960e41b81526110016004820152602401620012e4565b6001600160a01b0380821660009081526043602052604090205416620055f1603f8262008cf9565b6200560f5760405163056e881160e01b815260040160405180910390fd5b6001600160a01b038181166000908152604160205260408082206002810154603b54925163045bc4d160e41b81526004810193909352909316906345bc4d10906024016020604051808303816000875af115801562005672573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906200569891906200a211565b90506000603d5442620056ac91906200a1fb565b9050620056ba838262008da4565b836001600160a01b03167f6e9a2ee7aee95665e3a774a212eb11441b217e3e4656ab9563793094689aabb282846001604051620056fa939291906200a22b565b60405180910390a26002830154604051633041949b60e01b815261200591633041949b9162005738916001600160a01b03169088906004016200a198565b600060405180830381600087803b1580156200575357600080fd5b505af115801562005768573d6000803e3d6000fd5b505050505050505050565b600054610100900460ff1615808015620057945750600054600160ff909116105b80620057b05750303b158015620057b0575060005460ff166001145b620058155760405162461bcd60e51b815260206004820152602e60248201527f496e697469616c697a61626c653a20636f6e747261637420697320616c72656160448201526d191e481a5b9a5d1a585b1a5e995960921b6064820152608401620012e4565b6000805460ff19166001179055801562005839576000805461ff0019166101001790555b3341146200585a5760405163022d8c9560e31b815260040160405180910390fd5b3a156200587a576040516383f1b1d360e01b815260040160405180910390fd5b611388603555686c6b935b8bbd400000603655670de0b6b3a7640000603755602d60385562093a806039556002603a819055678ac7230489e80000603b55680ad78ebc5ac6200000603c556202a300603d5562278d00603e55604a55620058f57308e68ec70fa3b629784fdb28887e206ce8561e0862009474565b80156200190f576000805461ff0019169055604051600181527f7f26b83ff96e1f2b6a682f133852f6798a09c465da95921460cefb38474024989060200160405180910390a150565b33612000146200596657604051630f22c43960e41b81526120006004820152602401620012e4565b60405162461bcd60e51b815260206004820152600a60248201526919195c1c9958d85d195960b21b6044820152606401620012e4565b600054630100000090046001600160a01b03163314620059cf576040516306fbb1e360e01b815260040160405180910390fd5b60005462010000900460ff1615620059fa57604051631785c68160e01b815260040160405180910390fd5b6000805462ff00001916620100001781556040517f9e87fac88ff661f02d44f95383c817fece4bce600a3dab7a54406878b965e7529190a1565b600062005a43603f8462008cf9565b62005a615760405163056e881160e01b815260040160405180910390fd5b6001600160a01b0383811660009081526041602052604090819020600201549051636bbf224960e01b815260048101859052911690636bbf2249906024015b602060405180830381865afa15801562005abe573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019062005ae491906200a211565b90505b92915050565b60005462010000900460ff161562005b1857604051631785c68160e01b815260040160405180910390fd5b3360009081526001602052604090205460ff161562005b4a5760405163b1d02c3d60e01b815260040160405180910390fd5b8162005b58603f8262008cf9565b62005b765760405163056e881160e01b815260040160405180910390fd5b603754349081101562005b9c5760405163dc6f0bdd60e01b815260040160405180910390fd5b6001600160a01b038085166000908152604160209081526040808320815161018081018352815486168152600182015486169381019390935260028101549094169082015260038301546060820152600483018054339491608084019162005c04906200a162565b80601f016020809104026020016040519081016040528092919081815260200182805462005c32906200a162565b801562005c835780601f1062005c575761010080835404028352916020019162005c83565b820191906000526020600020905b81548152906001019060200180831162005c6557829003601f168201915b505050505081526020016005820160405180608001604052908160008201805462005cae906200a162565b80601f016020809104026020016040519081016040528092919081815260200182805462005cdc906200a162565b801562005d2d5780601f1062005d015761010080835404028352916020019162005d2d565b820191906000526020600020905b81548152906001019060200180831162005d0f57829003601f168201915b5050505050815260200160018201805462005d48906200a162565b80601f016020809104026020016040519081016040528092919081815260200182805462005d76906200a162565b801562005dc75780601f1062005d9b5761010080835404028352916020019162005dc7565b820191906000526020600020905b81548152906001019060200180831162005da957829003601f168201915b5050505050815260200160028201805462005de2906200a162565b80601f016020809104026020016040519081016040528092919081815260200182805462005e10906200a162565b801562005e615780601f1062005e355761010080835404028352916020019162005e61565b820191906000526020600020905b81548152906001019060200180831162005e4357829003601f168201915b5050505050815260200160038201805462005e7c906200a162565b80601f016020809104026020016040519081016040528092919081815260200182805462005eaa906200a162565b801562005efb5780601f1062005ecf5761010080835404028352916020019162005efb565b820191906000526020600020905b81548152906001019060200180831162005edd57829003601f168201915b505050919092525050508152604080516060808201835260098501546001600160401b038082168452600160401b82048116602080860191909152600160801b9092041683850152840191909152600a84015460ff16151582840152600b84015490830152600c8301546080830152600d8301546001600160a01b031660a0830152805161026081019182905260c09092019190600e84019060139082845b81548152602001906001019080831162005f9a5750505050508152505090508060e00151801562005fdd5750856001600160a01b0316826001600160a01b031614155b1562005ffc57604051636468920360e01b815260040160405180910390fd5b60408082015190516317066a5760e21b81526001600160a01b0384811660048301526000921690635c19a95c90869060240160206040518083038185885af11580156200604d573d6000803e3d6000fd5b50505050506040513d601f19601f820116820180604052508101906200607491906200a211565b9050826001600160a01b0316876001600160a01b03167f24d7bda8602b916d64417f0dbfe2e2e88ec9b1157bd9f596dfdb91ba26624e048387604051620060c5929190918252602082015260400190565b60405180910390a36040808301519051633041949b60e01b815261200591633041949b91620060fa919087906004016200a198565b600060405180830381600087803b1580156200611557600080fd5b505af11580156200612a573d6000803e3d6000fd5b50505050851562001908576040516372f6ad8f60e11b81526120059063e5ed5b1e906200615e9086908b906004016200a198565b600060405180830381600087803b1580156200617957600080fd5b505af11580156200618e573d6000803e3d6000fd5b5050505050505050505050565b60005462010000900460ff1615620061c657604051631785c68160e01b815260040160405180910390fd5b3360009081526001602052604090205460ff1615620061f85760405163b1d02c3d60e01b815260040160405180910390fd5b6200620262008e98565b6200620f603f8262008cf9565b6200622d5760405163056e881160e01b815260040160405180910390fd5b60006200623962008e98565b6001600160a01b0381166000908152604f6020526040812080549293509190859003620063105760005b81811015620062e457836001600160a01b03167f08e60c1b84aab23d99a7262015e647d5ffd6c6e08f78205e1df6774c48e1427a848381548110620062ac57620062ac6200a266565b9060005260206000200154604051620062c791815260200190565b60405180910390a280620062db816200a27c565b91505062006263565b506001600160a01b0383166000908152604f60205260408120620063089162009766565b505050505050565b60005b858110156200646e5760008787838181106200633357620063336200a266565b90506020020135905060005b838110156200645657818582815481106200635e576200635e6200a266565b9060005260206000200154036200644157846200637d6001866200a298565b815481106200639057620063906200a266565b9060005260206000200154858281548110620063b057620063b06200a266565b906000526020600020018190555084805480620063d157620063d16200a6ad565b600190038181906000526020600020016000905590558380620063f4906200a6c3565b945050856001600160a01b03167f08e60c1b84aab23d99a7262015e647d5ffd6c6e08f78205e1df6774c48e1427a836040516200643391815260200190565b60405180910390a262006456565b806200644d816200a27c565b9150506200633f565b5050808062006465906200a27c565b91505062006313565b50815460000362006308576001600160a01b0383166000908152604f60205260408120620063089162009766565b505050565b620064cd6040518060800160405280606081526020016060815260200160608152602001606081525090565b81620064db603f8262008cf9565b620064f95760405163056e881160e01b815260040160405180910390fd5b6001600160a01b0383166000908152604160205260409081902081516080810190925260050180548290829062006530906200a162565b80601f01602080910402602001604051908101604052809291908181526020018280546200655e906200a162565b8015620065af5780601f106200658357610100808354040283529160200191620065af565b820191906000526020600020905b8154815290600101906020018083116200659157829003601f168201915b50505050508152602001600182018054620065ca906200a162565b80601f0160208091040260200160405190810160405280929190818152602001828054620065f8906200a162565b8015620066495780601f106200661d5761010080835404028352916020019162006649565b820191906000526020600020905b8154815290600101906020018083116200662b57829003601f168201915b5050505050815260200160028201805462006664906200a162565b80601f016020809104026020016040519081016040528092919081815260200182805462006692906200a162565b8015620066e35780601f10620066b757610100808354040283529160200191620066e3565b820191906000526020600020905b815481529060010190602001808311620066c557829003601f168201915b50505050508152602001600382018054620066fe906200a162565b80601f01602080910402602001604051908101604052809291908181526020018280546200672c906200a162565b80156200677d5780601f1062006751576101008083540402835291602001916200677d565b820191906000526020600020905b8154815290600101906020018083116200675f57829003601f168201915b505050505081525050915050919050565b60005462010000900460ff1615620067b957604051631785c68160e01b815260040160405180910390fd5b3360009081526001602052604090205460ff1615620067eb5760405163b1d02c3d60e01b815260040160405180910390fd5b620067f782826200950d565b5050565b33611007146200682357604051630f22c43960e41b81526110076004820152602401620012e4565b620068906040518060400160405280601081526020016f1d1c985b9cd9995c91d85cd31a5b5a5d60821b81525085858080601f0160208091040260200160405190810160405280939291908181526020018383808284376000920191909152509293925050620096199050565b156200694b5760208114620068c25783838383604051630a5a604160e01b8152600401620012e494939291906200a6dd565b604080516020601f840181900481028201810190925282815260009162006905918585808385018382808284376000920191909152509293925050620096769050565b90506108fc81108062006919575061271081115b15620069425784848484604051630a5a604160e01b8152600401620012e494939291906200a6dd565b60355562007768565b620069bc6040518060400160405280601481526020017336b4b729b2b6332232b632b3b0ba34b7b721272160611b81525085858080601f0160208091040260200160405190810160405280939291908181526020018383808284376000920191909152509293925050620096199050565b1562006a865760208114620069ee5783838383604051630a5a604160e01b8152600401620012e494939291906200a6dd565b604080516020601f840181900481028201810190925282815260009162006a31918585808385018382808284376000920191909152509293925050620096769050565b9050683635c9adc5dea0000081108062006a54575069152d02c7e14af680000081115b1562006a7d5784848484604051630a5a604160e01b8152600401620012e494939291906200a6dd565b60365562007768565b62006af9604051806040016040528060168152602001756d696e44656c65676174696f6e424e424368616e676560501b81525085858080601f0160208091040260200160405190810160405280939291908181526020018383808284376000920191909152509293925050620096199050565b1562006bc0576020811462006b2b5783838383604051630a5a604160e01b8152600401620012e494939291906200a6dd565b604080516020601f840181900481028201810190925282815260009162006b6e918585808385018382808284376000920191909152509293925050620096769050565b905067016345785d8a000081108062006b8e5750678ac7230489e8000081115b1562006bb75784848484604051630a5a604160e01b8152600401620012e494939291906200a6dd565b60375562007768565b62006c31604051806040016040528060148152602001736d6178456c656374656456616c696461746f727360601b81525085858080601f0160208091040260200160405190810160405280939291908181526020018383808284376000920191909152509293925050620096199050565b1562006ce9576020811462006c635783838383604051630a5a604160e01b8152600401620012e494939291906200a6dd565b604080516020601f840181900481028201810190925282815260009162006ca6918585808385018382808284376000920191909152509293925050620096769050565b905080158062006cb757506101f481115b1562006ce05784848484604051630a5a604160e01b8152600401620012e494939291906200a6dd565b60385562007768565b62006d526040518060400160405280600c81526020016b1d5b989bdb9914195c9a5bd960a21b81525085858080601f0160208091040260200160405190810160405280939291908181526020018383808284376000920191909152509293925050620096199050565b1562006e0f576020811462006d845783838383604051630a5a604160e01b8152600401620012e494939291906200a6dd565b604080516020601f840181900481028201810190925282815260009162006dc7918585808385018382808284376000920191909152509293925050620096769050565b90506203f48081108062006ddd575062278d0081115b1562006e065784848484604051630a5a604160e01b8152600401620012e494939291906200a6dd565b60395562007768565b62006e7d60405180604001604052806011815260200170726564656c65676174654665655261746560781b81525085858080601f0160208091040260200160405190810160405280939291908181526020018383808284376000920191909152509293925050620096199050565b1562006f2a576020811462006eaf5783838383604051630a5a604160e01b8152600401620012e494939291906200a6dd565b604080516020601f840181900481028201810190925282815260009162006ef2918585808385018382808284376000920191909152509293925050620096769050565b9050606481111562006f215784848484604051630a5a604160e01b8152600401620012e494939291906200a6dd565b603a5562007768565b62006f9a60405180604001604052806013815260200172191bdddb9d1a5b5954db185cda105b5bdd5b9d606a1b81525085858080601f0160208091040260200160405190810160405280939291908181526020018383808284376000920191909152509293925050620096199050565b156200705c576020811462006fcc5783838383604051630a5a604160e01b8152600401620012e494939291906200a6dd565b604080516020601f84018190048102820181019092528281526000916200700f918585808385018382808284376000920191909152509293925050620096769050565b9050670de0b6b3a76400008110806200702a5750603c548110155b15620070535784848484604051630a5a604160e01b8152600401620012e494939291906200a6dd565b603b5562007768565b620070ca6040518060400160405280601181526020017019995b1bdb9e54db185cda105b5bdd5b9d607a1b81525085858080601f0160208091040260200160405190810160405280939291908181526020018383808284376000920191909152509293925050620096199050565b156200718c5760208114620070fc5783838383604051630a5a604160e01b8152600401620012e494939291906200a6dd565b604080516020601f84018190048102820181019092528281526000916200713f918585808385018382808284376000920191909152509293925050620096769050565b9050678ac7230489e800008110806200715a5750603b548111155b15620071835784848484604051630a5a604160e01b8152600401620012e494939291906200a6dd565b603c5562007768565b620071f96040518060400160405280601081526020016f646f776e74696d654a61696c54696d6560801b81525085858080601f0160208091040260200160405190810160405280939291908181526020018383808284376000920191909152509293925050620096199050565b15620072b657602081146200722b5783838383604051630a5a604160e01b8152600401620012e494939291906200a6dd565b604080516020601f84018190048102820181019092528281526000916200726e918585808385018382808284376000920191909152509293925050620096769050565b905062015180811080620072845750603e548110155b15620072ad5784848484604051630a5a604160e01b8152600401620012e494939291906200a6dd565b603d5562007768565b620073216040518060400160405280600e81526020016d66656c6f6e794a61696c54696d6560901b81525085858080601f0160208091040260200160405190810160405280939291908181526020018383808284376000920191909152509293925050620096199050565b15620073de5760208114620073535783838383604051630a5a604160e01b8152600401620012e494939291906200a6dd565b604080516020601f840181900481028201810190925282815260009162007396918585808385018382808284376000920191909152509293925050620096769050565b90506203f480811080620073ac5750603d548111155b15620073d55784848484604051630a5a604160e01b8152600401620012e494939291906200a6dd565b603e5562007768565b620074586040518060400160405280601c81526020017f6d617846656c6f6e794265747765656e42726561746865426c6f636b0000000081525085858080601f0160208091040260200160405190810160405280939291908181526020018383808284376000920191909152509293925050620096199050565b156200750457602081146200748a5783838383604051630a5a604160e01b8152600401620012e494939291906200a6dd565b604080516020601f8401819004810282018101909252828152600091620074cd918585808385018382808284376000920191909152509293925050620096769050565b905080600003620074fb5784848484604051630a5a604160e01b8152600401620012e494939291906200a6dd565b604a5562007768565b620075726040518060400160405280601181526020017039ba30b5b2a43ab1283937ba32b1ba37b960791b81525085858080601f0160208091040260200160405190810160405280939291908181526020018383808284376000920191909152509293925050620096199050565b15620076325760148114620075a45783838383604051630a5a604160e01b8152600401620012e494939291906200a6dd565b6000620075ec601484848080601f0160208091040260200160405190810160405280939291908181526020018383808284376000920191909152509293925050620096769050565b90506001600160a01b038116620076205784848484604051630a5a604160e01b8152600401620012e494939291906200a6dd565b6200762b816200967b565b5062007768565b620076996040518060400160405280600a8152602001696d61784e6f646549447360b01b81525085858080601f0160208091040260200160405190810160405280939291908181526020018383808284376000920191909152509293925050620096199050565b15620077455760208114620076cb5783838383604051630a5a604160e01b8152600401620012e494939291906200a6dd565b604080516020601f84018190048102820181019092528281526000916200770e918585808385018382808284376000920191909152509293925050620096769050565b9050806000036200773c5784848484604051630a5a604160e01b8152600401620012e494939291906200a6dd565b604e5562007768565b838383836040516325ee20d560e21b8152600401620012e494939291906200a6dd565b7ff1ce9b2cbf50eeb05769a29e2543fd350cab46894a7dd9978a12d534bb20e633848484846040516200779f94939291906200a6dd565b60405180910390a150505050565b60005462010000900460ff1615620077d857604051631785c68160e01b815260040160405180910390fd5b3360009081526001602052604090205460ff16156200780a5760405163b1d02c3d60e01b815260040160405180910390fd5b816000816001600160401b038111156200782857620078286200993b565b60405190808252806020026020018201604052801562007852578160200160208202803683370190505b5090506000805b8381101562007950576200789b8787838181106200787b576200787b6200a266565b9050602002016020810190620078929190620097cc565b603f9062008cf9565b620078b95760405163056e881160e01b815260040160405180910390fd5b60416000888884818110620078d257620078d26200a266565b9050602002016020810190620078e99190620097cc565b6001600160a01b03908116825260208201929092526040016000206002015484519116925082908490839081106200792557620079256200a266565b6001600160a01b039092166020928302919091019091015262007948816200a27c565b905062007859565b50604051634484077560e01b8152612005906344840775906200337d90859088906004016200a2c8565b60608060006200798b603f62009071565b90508085101562007b4f578315620079a45783620079a6565b805b9350600084620079b787846200a298565b11620079cf57620079c986836200a298565b620079d1565b845b9050806001600160401b03811115620079ee57620079ee6200993b565b60405190808252806020026020018201604052801562007a18578160200160208202803683370190505b509350806001600160401b0381111562007a365762007a366200993b565b60405190808252806020026020018201604052801562007a60578160200160208202803683370190505b50925060005b8181101562007b4c5762007a7f6200453882896200a1fb565b85828151811062007a945762007a946200a266565b60200260200101906001600160a01b031690816001600160a01b0316815250506041600086838151811062007acd5762007acd6200a266565b60200260200101516001600160a01b03166001600160a01b0316815260200190815260200160002060020160009054906101000a90046001600160a01b031684828151811062007b215762007b216200a266565b6001600160a01b039092166020928302919091019091015262007b44816200a27c565b905062007a66565b50505b9250925092565b60008162007b66603f8262008cf9565b62007b845760405163056e881160e01b815260040160405180910390fd5b50506001600160a01b03166000908152604160205260409020600c015490565b336110011462007bcc57604051630f22c43960e41b81526110016004820152602401620012e4565b60005462010000900460ff161562007bf757604051631785c68160e01b815260040160405180910390fd5b6001600160a01b038082166000908152604360205260409020541662007c1f603f8262008cf9565b62007c3d5760405163056e881160e01b815260040160405180910390fd5b6001600160a01b03811660009081526041602052604081209062007c6562015180426200a1d8565b604a546000828152604b60205260409020549192501162007c995760405163bd52fcdb60e01b815260040160405180910390fd5b6000818152604b6020526040812080546001929062007cba9084906200a1fb565b90915550506001600160a01b0384166000908152604460205260409020541580159062007d0f57506001600160a01b038416600090815260446020526040902054429062007d0d9062015180906200a1fb565b105b1562007d2e576040516330abb81d60e21b815260040160405180910390fd5b60008062007d3e85600062008d1c565b915091508162007d6157604051631b919bb160e11b815260040160405180910390fd5b6002840154603c5460405163045bc4d160e41b815260048101919091526000916001600160a01b0316906345bc4d10906024016020604051808303816000875af115801562007db4573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019062007dda91906200a211565b905062007de8858362008da4565b84546040516335409f7f60e01b81526001600160a01b039091166004820152611000906335409f7f90602401600060405180830381600087803b15801562007e2f57600080fd5b505af115801562007e44573d6000803e3d6000fd5b50505050856001600160a01b03167f6e9a2ee7aee95665e3a774a212eb11441b217e3e4656ab9563793094689aabb28383600060405162007e88939291906200a22b565b60405180910390a26002850154604051633041949b60e01b815261200591633041949b916200615e916001600160a01b0316908a906004016200a198565b6001600160a01b038082166000908152604160209081526040808320815161018081018352815486168152600182015486169381019390935260028101549094169082015260038301546060820152600483018054929384938493849390929160808401919062007f37906200a162565b80601f016020809104026020016040519081016040528092919081815260200182805462007f65906200a162565b801562007fb65780601f1062007f8a5761010080835404028352916020019162007fb6565b820191906000526020600020905b81548152906001019060200180831162007f9857829003601f168201915b505050505081526020016005820160405180608001604052908160008201805462007fe1906200a162565b80601f01602080910402602001604051908101604052809291908181526020018280546200800f906200a162565b8015620080605780601f10620080345761010080835404028352916020019162008060565b820191906000526020600020905b8154815290600101906020018083116200804257829003601f168201915b505050505081526020016001820180546200807b906200a162565b80601f0160208091040260200160405190810160405280929190818152602001828054620080a9906200a162565b8015620080fa5780601f10620080ce57610100808354040283529160200191620080fa565b820191906000526020600020905b815481529060010190602001808311620080dc57829003601f168201915b5050505050815260200160028201805462008115906200a162565b80601f016020809104026020016040519081016040528092919081815260200182805462008143906200a162565b8015620081945780601f10620081685761010080835404028352916020019162008194565b820191906000526020600020905b8154815290600101906020018083116200817657829003601f168201915b50505050508152602001600382018054620081af906200a162565b80601f0160208091040260200160405190810160405280929190818152602001828054620081dd906200a162565b80156200822e5780601f1062008202576101008083540402835291602001916200822e565b820191906000526020600020905b8154815290600101906020018083116200821057829003601f168201915b505050919092525050508152604080516060808201835260098501546001600160401b038082168452600160401b82048116602080860191909152600160801b9092041683850152840191909152600a84015460ff16151582840152600b84015490830152600c8301546080830152600d8301546001600160a01b031660a0830152805161026081019182905260c09092019190600e84019060139082845b815481526020019060010190808311620082cd5750505091909252505050606081015160e0820151610100909201519097919650945092505050565b60005462010000900460ff16156200833457604051631785c68160e01b815260040160405180910390fd5b3360009081526001602052604090205460ff1615620083665760405163b1d02c3d60e01b815260040160405180910390fd5b6200837062008f12565b6200837d603f8262008cf9565b6200839b5760405163056e881160e01b815260040160405180910390fd5b6000620083a762008f12565b6001600160a01b0381166000908152604160205260409020600c810154919250904290620083da9062015180906200a1fb565b1115620083fa57604051631f92cdbd60e11b815260040160405180910390fd5b6005810180546200840b906200a162565b80601f016020809104026020016040519081016040528092919081815260200182805462008439906200a162565b80156200848a5780601f106200845e576101008083540402835291602001916200848a565b820191906000526020600020905b8154815290600101906020018083116200846c57829003601f168201915b5050508287525085916005840191508190620084a790826200a713565b5060208201516001820190620084be90826200a713565b5060408201516002820190620084d590826200a713565b5060608201516003820190620084ec90826200a713565b505042600c830155506040516001600160a01b038316907f85d6366b336ade7f106987ec7a8eac1e8799e508aeab045a39d2f63e0dc969d990600090a250505050565b60005462010000900460ff16156200855a57604051631785c68160e01b815260040160405180910390fd5b3360009081526001602052604090205460ff16156200858c5760405163b1d02c3d60e01b815260040160405180910390fd5b828114620085ad576040516341abc80160e01b815260040160405180910390fd5b60005b838110156200861e576200860b858583818110620085d257620085d26200a266565b9050602002016020810190620085e99190620097cc565b848484818110620085fe57620085fe6200a266565b905060200201356200950d565b62008616816200a27c565b9050620085b0565b5050505050565b6001600160a01b038082166000908152604160209081526040808320815161018081018352815486168152600182015486169381019390935260028101549094169082015260038301546060820152600483018054929384939091608084019162008690906200a162565b80601f0160208091040260200160405190810160405280929190818152602001828054620086be906200a162565b80156200870f5780601f10620086e3576101008083540402835291602001916200870f565b820191906000526020600020905b815481529060010190602001808311620086f157829003601f168201915b50505050508152602001600582016040518060800160405290816000820180546200873a906200a162565b80601f016020809104026020016040519081016040528092919081815260200182805462008768906200a162565b8015620087b95780601f106200878d57610100808354040283529160200191620087b9565b820191906000526020600020905b8154815290600101906020018083116200879b57829003601f168201915b50505050508152602001600182018054620087d4906200a162565b80601f016020809104026020016040519081016040528092919081815260200182805462008802906200a162565b8015620088535780601f10620088275761010080835404028352916020019162008853565b820191906000526020600020905b8154815290600101906020018083116200883557829003601f168201915b505050505081526020016002820180546200886e906200a162565b80601f01602080910402602001604051908101604052809291908181526020018280546200889c906200a162565b8015620088ed5780601f10620088c157610100808354040283529160200191620088ed565b820191906000526020600020905b815481529060010190602001808311620088cf57829003601f168201915b5050505050815260200160038201805462008908906200a162565b80601f016020809104026020016040519081016040528092919081815260200182805462008936906200a162565b8015620089875780601f106200895b5761010080835404028352916020019162008987565b820191906000526020600020905b8154815290600101906020018083116200896957829003601f168201915b505050919092525050508152604080516060808201835260098501546001600160401b038082168452600160401b82048116602080860191909152600160801b9092041683850152840191909152600a84015460ff16151582840152600b84015490830152600c8301546080830152600d8301546001600160a01b031660a0830152805161026081019182905260c09092019190600e84019060139082845b81548152602001906001019080831162008a265750505091909252505050604001519392505050565b600062008a5e603f8462008cf9565b62008a7c5760405163056e881160e01b815260040160405180910390fd5b6001600160a01b038381166000908152604160205260409081902060020154905163aa1966cd60e01b81526004810185905291169063aa1966cd9060240162005aa0565b60005462010000900460ff161562008aeb57604051631785c68160e01b815260040160405180910390fd5b3360009081526001602052604090205460ff161562008b1d5760405163b1d02c3d60e01b815260040160405180910390fd5b62008b2762008f12565b62008b34603f8262008cf9565b62008b525760405163056e881160e01b815260040160405180910390fd5b600062008b5e62008f12565b905062008b6f81878787876200922c565b62008b8d57604051631647e3cb60e11b815260040160405180910390fd5b60006001600160a01b03166045878760405162008bac9291906200a1b2565b908152604051908190036020019020546001600160a01b03161462008be4576040516311fdb94760e01b815260040160405180910390fd5b6001600160a01b0381166000908152604160205260409020600c810154429062008c139062015180906200a1fb565b111562008c3357604051631f92cdbd60e11b815260040160405180910390fd5b4260468260040160405162008c4991906200a7db565b908152604051908190036020019020556004810162008c6a8789836200a3c6565b5042600c820155604051829060459062008c88908a908a906200a1b2565b90815260405190819003602001812080546001600160a01b039384166001600160a01b0319909116179055908316907f783156582145bd0ff7924fae6953ba054cf1233eb60739a200ddb10de068ff0d9062008ce8908a908a906200a697565b60405180910390a250505050505050565b6001600160a01b0381166000908152600183016020526040812054151562005ae4565b6000806000848460405160200162008d369291906200a859565b60408051601f1981840301815291815281516020928301206000818152604c9093529120549091504281111562008d7657600080935093505050620026aa565b603e5462008d8590426200a1fb565b6000928352604c60205260409092208290555060019590945092505050565b6000600162008db4603f62009071565b62008dc091906200a298565b604954108015915062008e0c5760018301546040516001600160a01b03909116907f2afdc18061ac21cff7d9f11527ab9c8dec6fabd4edf6f894ed634bebd6a20d4590600090a2505050565b82600b015482111562008e2157600b83018290555b600a83015460ff166200649c57600a8301805460ff191660019081179091556049805460009062008e549084906200a1fb565b909155505060018301546040516001600160a01b03909116907f4905ac32602da3fb8b4b7b00c285e5fc4c6c2308cc908b4a1e4e9625a29c90a390600090a2505050565b336000908152604360205260408120546001600160a01b03161580159062008ecd575033600090815260446020526040902054155b1562008ef05750336000908152604360205260409020546001600160a01b031690565b62008efa62008f12565b905090565b604e5460000362008f10576005604e555b565b336000908152604d60205260408120546001600160a01b03161562008f4e5750336000908152604d60205260409020546001600160a01b031690565b503390565b6001600160a01b0381166000908152604160205260409020600a81015460ff161562008f7d575050565b6036546002820154604051630913db4760e01b81526001600160a01b03858116600483015290911690630913db4790602401602060405180830381865afa15801562008fcd573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019062008ff391906200a211565b1015620067f7576200901581603d54426200900f91906200a1fb565b62008da4565b80546040516335409f7f60e01b81526001600160a01b039091166004820152611000906335409f7f90602401600060405180830381600087803b1580156200905c57600080fd5b505af115801562006308573d6000803e3d6000fd5b600062005ae7825490565b600062005ae48383620096e7565b600080829050600381511080620090a2575060098151115b15620090b15750600092915050565b604181600081518110620090c957620090c96200a266565b016020015160f81c1080620090fb5750605a81600081518110620090f157620090f16200a266565b016020015160f81c115b156200910a5750600092915050565b60015b8151811015620092225760308282815181106200912e576200912e6200a266565b016020015160f81c10806200915f575060398282815181106200915557620091556200a266565b016020015160f81c115b8015620091af575060418282815181106200917e576200917e6200a266565b016020015160f81c1080620091af5750605a828281518110620091a557620091a56200a266565b016020015160f81c115b8015620091ff57506061828281518110620091ce57620091ce6200a266565b016020015160f81c1080620091ff5750607a828281518110620091f557620091f56200a266565b016020015160f81c115b156200920f575060009392505050565b6200921a816200a27c565b90506200910d565b5060019392505050565b600060308414158062009240575060608214155b156200924f5750600062009353565b6000868686466040516020016200926a94939291906200a8a3565b60408051808303601f1901815282825280516020918201208184528383019092529092506000919060208201818036833701905050905081602082015260008186868a8a604051602001620092c49594939291906200a8d0565b60408051808303601f190181526001808452838301909252925060009190602082018180368337019050509050815160016020830182602086016066600019fa6200930e57600080fd5b506000816000815181106200932757620093276200a266565b016020015160f81c905060018114620093495760009550505050505062009353565b6001955050505050505b95945050505050565b60008061200361dead604051620093739062009786565b6001600160a01b03928316815291166020820152606060408201819052600090820152608001604051809103906000f080158015620093b6573d6000803e3d6000fd5b509050806001600160a01b031663f399e22e3486866040518463ffffffff1660e01b8152600401620093ea9291906200a908565b6000604051808303818588803b1580156200940457600080fd5b505af115801562009419573d6000803e3d6000fd5b50506040516001600160a01b038086169450881692507fd481492e4e93bb36b4c12a5af93f03be3bf04b454dfbc35dd2663fa26f44d5b09150600090a39392505050565b600062005ae4836001600160a01b03841662009714565b600054610100900460ff16620094e15760405162461bcd60e51b815260206004820152602b60248201527f496e697469616c697a61626c653a20636f6e7472616374206973206e6f74206960448201526a6e697469616c697a696e6760a81b6064820152608401620012e4565b600080546001600160a01b039092166301000000026301000000600160b81b0319909216919091179055565b816200951b603f8262008cf9565b620095395760405163056e881160e01b815260040160405180910390fd5b6001600160a01b03838116600090815260416020526040808220600201549051635569f64b60e11b8152336004820152602481018690529192169063aad3ec96906044016020604051808303816000875af11580156200959d573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190620095c391906200a211565b9050336001600160a01b0316846001600160a01b03167ff7a40077ff7a04c7e61f6f26fb13774259ddf1b6bce9ecf26a8276cdd3992683836040516200960b91815260200190565b60405180910390a350505050565b6000816040516020016200962e91906200a92e565b60405160208183030381529060405280519060200120836040516020016200965791906200a92e565b6040516020818303038152906040528051906020012014905092915050565b015190565b600080546040516001600160a01b0380851693630100000090930416917f44fc1b38a4abaa91ebd1b628a5b259a698f86238c8217d68f516e87769c60c0b91a3600080546001600160a01b039092166301000000026301000000600160b81b0319909216919091179055565b60008260000182815481106200970157620097016200a266565b9060005260206000200154905092915050565b60008181526001830160205260408120546200975d5750815460018181018455600084815260208082209093018490558454848252828601909352604090209190915562005ae7565b50600062005ae7565b50805460008255906000526020600020908101906200190f919062009794565b610e96806200a94d83390190565b5b80821115620097ab576000815560010162009795565b5090565b80356001600160a01b0381168114620097c757600080fd5b919050565b600060208284031215620097df57600080fd5b62005ae482620097af565b60008083601f840112620097fd57600080fd5b5081356001600160401b038111156200981557600080fd5b602083019150836020828501011115620026aa57600080fd5b600080602083850312156200984257600080fd5b82356001600160401b038111156200985957600080fd5b6200986785828601620097ea565b90969095509350505050565b6000806000604084860312156200988957600080fd5b833560ff811681146200989b57600080fd5b925060208401356001600160401b03811115620098b757600080fd5b620098c586828701620097ea565b9497909650939450505050565b60005b83811015620098ef578181015183820152602001620098d5565b50506000910152565b6000815180845262009912816020860160208601620098d2565b601f01601f19169290920160200192915050565b60208152600062005ae46020830184620098f8565b634e487b7160e01b600052604160045260246000fd5b604051608081016001600160401b03811182821017156200997657620099766200993b565b60405290565b60006001600160401b03808411156200999957620099996200993b565b604051601f8501601f19908116603f01168101908282118183101715620099c457620099c46200993b565b81604052809350858152868686011115620099de57600080fd5b858560208301376000602087830101525050509392505050565b60006020828403121562009a0b57600080fd5b81356001600160401b0381111562009a2257600080fd5b8201601f8101841362009a3457600080fd5b62009a45848235602084016200997c565b949350505050565b60008083601f84011262009a6057600080fd5b5081356001600160401b0381111562009a7857600080fd5b6020830191508360208260051b8501011115620026aa57600080fd5b6000806020838503121562009aa857600080fd5b82356001600160401b0381111562009abf57600080fd5b620098678582860162009a4d565b600081518084526020808501945080840160005b8381101562009b085781516001600160a01b03168752958201959082019060010162009ae1565b509495945050505050565b60408152600062009b28604083018562009acd565b6020838203818501528185518084528284019150828160051b8501018388016000805b8481101562009ba257878403601f19018652825180518086529088019088860190845b8181101562009b8c5783518352928a0192918a019160010162009b6e565b5050968801969450509186019160010162009b4b565b50919a9950505050505050505050565b6000806040838503121562009bc657600080fd5b62009bd183620097af565b946020939093013593505050565b80358015158114620097c757600080fd5b6000806000806080858703121562009c0757600080fd5b62009c1285620097af565b935062009c2260208601620097af565b92506040850135915062009c396060860162009bdf565b905092959194509250565b6001600160401b03811681146200190f57600080fd5b60006020828403121562009c6d57600080fd5b813562009c7a8162009c44565b9392505050565b6000806040838503121562009c9557600080fd5b50508035926020909101359150565b60808152600062009cb9608083018762009acd565b82810360208481019190915286518083528782019282019060005b8181101562009cf25784518352938301939183019160010162009cd4565b5050848103604086015286518082528282019350600581901b8201830183890160005b8381101562009d4757601f1985840301875262009d34838351620098f8565b9686019692509085019060010162009d15565b5050809550505050505082606083015295945050505050565b600080600080600080600087890360e081121562009d7d57600080fd5b62009d8889620097af565b975060208901356001600160401b038082111562009da557600080fd5b62009db38c838d01620097ea565b909950975060408b013591508082111562009dcd57600080fd5b62009ddb8c838d01620097ea565b90975095508591506060605f198401121562009df657600080fd5b60608b01945060c08b013592508083111562009e1157600080fd5b505088016080818b03121562009e2657600080fd5b8091505092959891949750929550565b6000806040838503121562009e4a57600080fd5b62009e5583620097af565b915062009e656020840162009bdf565b90509250929050565b60208152600082516080602084015262009e8c60a0840182620098f8565b90506020840151601f198085840301604086015262009eac8383620098f8565b9250604086015191508085840301606086015262009ecb8383620098f8565b9250606086015191508085840301608086015250620093538282620098f8565b6000806000806040858703121562009f0257600080fd5b84356001600160401b038082111562009f1a57600080fd5b62009f2888838901620097ea565b9096509450602087013591508082111562009f4257600080fd5b5062009f5187828801620097ea565b95989497509550505050565b60008060006040848603121562009f7357600080fd5b83356001600160401b0381111562009f8a57600080fd5b62009f988682870162009a4d565b909450925062009fad905060208501620097af565b90509250925092565b60608152600062009fcb606083018662009acd565b828103602084015262009fdf818662009acd565b915050826040830152949350505050565b600082601f8301126200a00257600080fd5b62005ae4838335602085016200997c565b6000602082840312156200a02657600080fd5b81356001600160401b03808211156200a03e57600080fd5b90830190608082860312156200a05357600080fd5b6200a05d62009951565b8235828111156200a06d57600080fd5b6200a07b8782860162009ff0565b8252506020830135828111156200a09157600080fd5b6200a09f8782860162009ff0565b6020830152506040830135828111156200a0b857600080fd5b6200a0c68782860162009ff0565b6040830152506060830135828111156200a0df57600080fd5b6200a0ed8782860162009ff0565b60608301525095945050505050565b600080600080604085870312156200a11357600080fd5b84356001600160401b03808211156200a12b57600080fd5b6200a1398883890162009a4d565b909650945060208701359150808211156200a15357600080fd5b5062009f518782880162009a4d565b600181811c908216806200a17757607f821691505b602082108103620020dc57634e487b7160e01b600052602260045260246000fd5b6001600160a01b0392831681529116602082015260400190565b8183823760009101908152919050565b634e487b7160e01b600052601160045260246000fd5b6000826200a1f657634e487b7160e01b600052601260045260246000fd5b500490565b8082018082111562005ae75762005ae76200a1c2565b6000602082840312156200a22457600080fd5b5051919050565b8381526020810183905260608101600383106200a25857634e487b7160e01b600052602160045260246000fd5b826040830152949350505050565b634e487b7160e01b600052603260045260246000fd5b6000600182016200a291576200a2916200a1c2565b5060010190565b8181038181111562005ae75762005ae76200a1c2565b808202811582820484141762005ae75762005ae76200a1c2565b6040815260006200a2dd604083018562009acd565b905060018060a01b03831660208301529392505050565b6001600160401b038281168282160390808211156200a317576200a3176200a1c2565b5092915050565b6000808335601e198436030181126200a33657600080fd5b8301803591506001600160401b038211156200a35157600080fd5b602001915036819003821315620026aa57600080fd5b601f8211156200649c57600081815260208120601f850160051c810160208610156200a3905750805b601f850160051c820191505b8181101562006308578281556001016200a39c565b600019600383901b1c191660019190911b1790565b6001600160401b038311156200a3e0576200a3e06200993b565b6200a3f8836200a3f183546200a162565b836200a367565b6000601f8411600181146200a42b57600085156200a4165750838201355b6200a42286826200a3b1565b8455506200861e565b600083815260209020601f19861690835b828110156200a45e57868501358255602094850194600190920191016200a43c565b50868210156200a47c5760001960f88860031b161c19848701351681555b505060018560011b0183555050505050565b6200a49a82836200a31e565b6001600160401b038111156200a4b4576200a4b46200993b565b6200a4cc816200a4c585546200a162565b856200a367565b6000601f8211600181146200a4ff57600083156200a4ea5750838201355b6200a4f684826200a3b1565b8655506200a55c565b600085815260209020601f19841690835b828110156200a53257868501358255602094850194600190920191016200a510565b50848210156200a5505760001960f88660031b161c19848701351681555b505060018360011b0185555b505050506200a56f60208301836200a31e565b6200a57f8183600186016200a3c6565b50506200a59060408301836200a31e565b6200a5a08183600286016200a3c6565b50506200a5b160608301836200a31e565b6200a5c18183600386016200a3c6565b50505050565b81356200a5d48162009c44565b6001600160401b03811690508154816001600160401b0319821617835560208401356200a6018162009c44565b6fffffffffffffffff0000000000000000604091821b166fffffffffffffffffffffffffffffffff198316841781178555908501356200a6418162009c44565b6001600160c01b0319929092169092179190911760809190911b67ffffffffffffffff60801b1617905550565b81835281816020850137506000828201602090810191909152601f909101601f19169091010190565b60208152600062009a456020830184866200a66e565b634e487b7160e01b600052603160045260246000fd5b6000816200a6d5576200a6d56200a1c2565b506000190190565b6040815260006200a6f36040830186886200a66e565b82810360208401526200a7088185876200a66e565b979650505050505050565b81516001600160401b038111156200a72f576200a72f6200993b565b6200a747816200a74084546200a162565b846200a367565b602080601f8311600181146200a77b57600084156200a7665750858301515b6200a77285826200a3b1565b86555062006308565b600085815260208120601f198616915b828110156200a7ac578886015182559484019460019091019084016200a78b565b50858210156200a7cb5787850151600019600388901b60f8161c191681555b5050505050600190811b01905550565b60008083546200a7eb816200a162565b600182811680156200a80657600181146200a81c576200a84d565b60ff19841687528215158302870194506200a84d565b8760005260208060002060005b858110156200a8445781548a8201529084019082016200a829565b50505082870194505b50929695505050505050565b6bffffffffffffffffffffffff198360601b1681526000600383106200a88f57634e487b7160e01b600052602160045260246000fd5b5060f89190911b6014820152601501919050565b6bffffffffffffffffffffffff198560601b16815282846014830137601492019182015260340192915050565b600086516200a8e4818460208b01620098d2565b82018587823760009086019081528385823760009301928352509095945050505050565b6001600160a01b038316815260406020820181905260009062009a4590830184620098f8565b600082516200a942818460208701620098d2565b919091019291505056fe608060405260405162000e9638038062000e96833981016040819052620000269162000497565b828162000036828260006200004d565b50620000449050826200008a565b505050620005ca565b6200005883620000e5565b600082511180620000665750805b1562000085576200008383836200012760201b620001691760201c565b505b505050565b7f7e644d79422f17c01e4894b5f4f588d331ebfa28653d42ae832dc59e38c9798f620000b562000156565b604080516001600160a01b03928316815291841660208301520160405180910390a1620000e2816200018f565b50565b620000f08162000244565b6040516001600160a01b038216907fbc7cd75a20ee27fd9adebab32041f755214dbc6bffa90cc0225b39da2e5c2d3b90600090a250565b60606200014f838360405180606001604052806027815260200162000e6f60279139620002f8565b9392505050565b60006200018060008051602062000e4f83398151915260001b6200037760201b620001951760201c565b546001600160a01b0316919050565b6001600160a01b038116620001fa5760405162461bcd60e51b815260206004820152602660248201527f455243313936373a206e65772061646d696e20697320746865207a65726f206160448201526564647265737360d01b60648201526084015b60405180910390fd5b806200022360008051602062000e4f83398151915260001b6200037760201b620001951760201c565b80546001600160a01b0319166001600160a01b039290921691909117905550565b6200025a816200037a60201b620001981760201c565b620002be5760405162461bcd60e51b815260206004820152602d60248201527f455243313936373a206e657720696d706c656d656e746174696f6e206973206e60448201526c1bdd08184818dbdb9d1c9858dd609a1b6064820152608401620001f1565b80620002237f360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc60001b6200037760201b620001951760201c565b6060600080856001600160a01b03168560405162000317919062000577565b600060405180830381855af49150503d806000811462000354576040519150601f19603f3d011682016040523d82523d6000602084013e62000359565b606091505b5090925090506200036d8683838762000389565b9695505050505050565b90565b6001600160a01b03163b151590565b60608315620003fd578251600003620003f5576001600160a01b0385163b620003f55760405162461bcd60e51b815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e74726163740000006044820152606401620001f1565b508162000409565b62000409838362000411565b949350505050565b815115620004225781518083602001fd5b8060405162461bcd60e51b8152600401620001f1919062000595565b80516001600160a01b03811681146200045657600080fd5b919050565b634e487b7160e01b600052604160045260246000fd5b60005b838110156200048e57818101518382015260200162000474565b50506000910152565b600080600060608486031215620004ad57600080fd5b620004b8846200043e565b9250620004c8602085016200043e565b60408501519092506001600160401b0380821115620004e657600080fd5b818601915086601f830112620004fb57600080fd5b8151818111156200051057620005106200045b565b604051601f8201601f19908116603f011681019083821181831017156200053b576200053b6200045b565b816040528281528960208487010111156200055557600080fd5b6200056883602083016020880162000471565b80955050505050509250925092565b600082516200058b81846020870162000471565b9190910192915050565b6020815260008251806020840152620005b681604085016020870162000471565b601f01601f19169190910160400192915050565b61087580620005da6000396000f3fe60806040523661001357610011610017565b005b6100115b61001f6101a7565b6001600160a01b0316330361015f5760606001600160e01b0319600035166364d3180d60e11b810161005a576100536101da565b9150610157565b63587086bd60e11b6001600160e01b031982160161007a57610053610231565b63070d7c6960e41b6001600160e01b031982160161009a57610053610277565b621eb96f60e61b6001600160e01b03198216016100b9576100536102a8565b63a39f25e560e01b6001600160e01b03198216016100d9576100536102e8565b60405162461bcd60e51b815260206004820152604260248201527f5472616e73706172656e745570677261646561626c6550726f78793a2061646d60448201527f696e2063616e6e6f742066616c6c6261636b20746f2070726f78792074617267606482015261195d60f21b608482015260a4015b60405180910390fd5b815160208301f35b6101676102fc565b565b606061018e83836040518060600160405280602781526020016108426027913961030c565b9392505050565b90565b6001600160a01b03163b151590565b60007fb53127684a568b3173ae13b9f8a6016e243e63b6e8ee1178d6a717850b5d61035b546001600160a01b0316919050565b60606101e4610384565b60006101f33660048184610695565b81019061020091906106db565b905061021d8160405180602001604052806000815250600061038f565b505060408051602081019091526000815290565b60606000806102433660048184610695565b810190610250919061070c565b915091506102608282600161038f565b604051806020016040528060008152509250505090565b6060610281610384565b60006102903660048184610695565b81019061029d91906106db565b905061021d816103bb565b60606102b2610384565b60006102bc6101a7565b604080516001600160a01b03831660208201529192500160405160208183030381529060405291505090565b60606102f2610384565b60006102bc610412565b610167610307610412565b610421565b6060600080856001600160a01b03168560405161032991906107f2565b600060405180830381855af49150503d8060008114610364576040519150601f19603f3d011682016040523d82523d6000602084013e610369565b606091505b509150915061037a86838387610445565b9695505050505050565b341561016757600080fd5b610398836104c6565b6000825111806103a55750805b156103b6576103b48383610169565b505b505050565b7f7e644d79422f17c01e4894b5f4f588d331ebfa28653d42ae832dc59e38c9798f6103e46101a7565b604080516001600160a01b03928316815291841660208301520160405180910390a161040f81610506565b50565b600061041c6105af565b905090565b3660008037600080366000845af43d6000803e808015610440573d6000f35b3d6000fd5b606083156104b45782516000036104ad576001600160a01b0385163b6104ad5760405162461bcd60e51b815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e7472616374000000604482015260640161014e565b50816104be565b6104be83836105d7565b949350505050565b6104cf81610601565b6040516001600160a01b038216907fbc7cd75a20ee27fd9adebab32041f755214dbc6bffa90cc0225b39da2e5c2d3b90600090a250565b6001600160a01b03811661056b5760405162461bcd60e51b815260206004820152602660248201527f455243313936373a206e65772061646d696e20697320746865207a65726f206160448201526564647265737360d01b606482015260840161014e565b807fb53127684a568b3173ae13b9f8a6016e243e63b6e8ee1178d6a717850b5d61035b80546001600160a01b0319166001600160a01b039290921691909117905550565b60007f360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc6101cb565b8151156105e75781518083602001fd5b8060405162461bcd60e51b815260040161014e919061080e565b6001600160a01b0381163b61066e5760405162461bcd60e51b815260206004820152602d60248201527f455243313936373a206e657720696d706c656d656e746174696f6e206973206e60448201526c1bdd08184818dbdb9d1c9858dd609a1b606482015260840161014e565b807f360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc61058e565b600080858511156106a557600080fd5b838611156106b257600080fd5b5050820193919092039150565b80356001600160a01b03811681146106d657600080fd5b919050565b6000602082840312156106ed57600080fd5b61018e826106bf565b634e487b7160e01b600052604160045260246000fd5b6000806040838503121561071f57600080fd5b610728836106bf565b9150602083013567ffffffffffffffff8082111561074557600080fd5b818501915085601f83011261075957600080fd5b81358181111561076b5761076b6106f6565b604051601f8201601f19908116603f01168101908382118183101715610793576107936106f6565b816040528281528860208487010111156107ac57600080fd5b8260208601602083013760006020848301015280955050505050509250929050565b60005b838110156107e95781810151838201526020016107d1565b50506000910152565b600082516108048184602087016107ce565b9190910192915050565b602081526000825180602084015261082d8160408501602087016107ce565b601f01601f1916919091016040019291505056fe416464726573733a206c6f772d6c6576656c2064656c65676174652063616c6c206661696c6564a164736f6c6343000811000ab53127684a568b3173ae13b9f8a6016e243e63b6e8ee1178d6a717850b5d6103416464726573733a206c6f772d6c6576656c2064656c65676174652063616c6c206661696c6564a164736f6c6343000811000a \ No newline at end of file diff --git a/core/systemcontracts/pasteur/rialto/GovernorContract b/core/systemcontracts/pasteur/rialto/GovernorContract new file mode 100644 index 0000000000..d8ac9bcb87 --- /dev/null +++ b/core/systemcontracts/pasteur/rialto/GovernorContract @@ -0,0 +1 @@ +6080604052600436106103e85760003560e01c80637b3c71d311610208578063c28bc2fa11610118578063deaaa7cc116100ab578063ece40cc11161007a578063ece40cc114610e19578063f23a6e6114610e39578063f8ce560a14610e65578063fc0c546a14610e85578063fe0d94c114610ea657600080fd5b8063deaaa7cc14610cda578063e23a9a5214610d0e578063ea0217cf14610dd9578063eb9019d414610df957600080fd5b8063da95691a116100e7578063da95691a14610c2f578063dd42a1dd14610c4f578063dd4e2ba514610c74578063ddf0b00914610cba57600080fd5b8063c28bc2fa14610bbd578063c59057e414610bd0578063d07f91e914610bf0578063d33219b414610c1057600080fd5b8063a7713a701161019b578063b187bd261161016a578063b187bd2614610b23578063b58131b014610b41578063bc197c8114610b56578063c01f9e3714610b82578063c170ec0b14610ba257600080fd5b8063a7713a7014610aae578063a890c91014610ac3578063ab58fb8e14610ae3578063ac43175114610b0357600080fd5b806384b0196e116101d757806384b0196e14610a2657806391ddadf414610a4e57806397c3d33414610a7a5780639a802a6d14610a8e57600080fd5b80637b3c71d3146109bc5780637d5e81e2146109dc5780638129fc1c146109fc5780638456cb5914610a1157600080fd5b806332b8113e116103035780634838d1651161029657806354fd4d501161026557806354fd4d5014610912578063567813881461093c5780635f398a141461095c57806360c4247f1461097c57806370b0f6601461099c57600080fd5b80634838d1651461087c5780634a49ac4c146108ac5780634bf5d7e9146108cc578063533ddd14146108e157600080fd5b806340e58ee5116102d257806340e58ee5146107d1578063417c73a7146107f15780634385963214610811578063452115d61461085c57600080fd5b806332b8113e146107455780633932abb11461076e5780633bccf4fd146107845780633e4f49e6146107a457600080fd5b8063150b7a021161037b5780632656227d1161034a5780632656227d146106975780632d63f693146106aa5780632fe3e261146106e1578063328dd9821461071557600080fd5b8063150b7a02146105f0578063160cbed71461063457806317977c611461065457806324bc1a641461068257600080fd5b8063046f7da2116103b7578063046f7da21461054357806306f3f9e61461055857806306fdde0314610578578063143489d01461059a57600080fd5b8063013cf08b1461045857806301ffc9a7146104d357806302a251a314610503578063034201811461052357600080fd5b3661045357306103f6610eb9565b6001600160a01b0316146104515760405162461bcd60e51b815260206004820152601f60248201527f476f7665726e6f723a206d7573742073656e6420746f206578656375746f720060448201526064015b60405180910390fd5b005b600080fd5b34801561046457600080fd5b50610478610473366004615c9f565b610ed3565b604080519a8b526001600160a01b0390991660208b0152978901969096526060880194909452608087019290925260a086015260c085015260e084015215156101008301521515610120820152610140015b60405180910390f35b3480156104df57600080fd5b506104f36104ee366004615cb8565b610f8e565b60405190151581526020016104ca565b34801561050f57600080fd5b50610195545b6040519081526020016104ca565b34801561052f57600080fd5b5061051561053e366004615dfe565b610f9f565b34801561054f57600080fd5b50610451611097565b34801561056457600080fd5b50610451610573366004615c9f565b611127565b34801561058457600080fd5b5061058d6111b2565b6040516104ca9190615ef4565b3480156105a657600080fd5b506105d86105b5366004615c9f565b60009081526101636020526040902054600160401b90046001600160a01b031690565b6040516001600160a01b0390911681526020016104ca565b3480156105fc57600080fd5b5061061b61060b366004615f1c565b630a85bd0160e11b949350505050565b6040516001600160e01b031990911681526020016104ca565b34801561064057600080fd5b5061051561064f3660046160f3565b611245565b34801561066057600080fd5b5061051561066f366004616182565b6102c36020526000908152604090205481565b34801561068e57600080fd5b50610515611330565b6105156106a53660046160f3565b611356565b3480156106b657600080fd5b506105156106c5366004615c9f565b600090815261016360205260409020546001600160401b031690565b3480156106ed57600080fd5b506105157fb3b3f3b703cd84ce352197dcff232b1b5d3cfb2025ce47cf04742d0651f1af8881565b34801561072157600080fd5b50610735610730366004615c9f565b611449565b6040516104ca9493929190616268565b34801561075157600080fd5b5061028f546040516001600160401b0390911681526020016104ca565b34801561077a57600080fd5b5061019454610515565b34801561079057600080fd5b5061051561079f3660046162b5565b6116db565b3480156107b057600080fd5b506107c46107bf366004615c9f565b611751565b6040516104ca9190616319565b3480156107dd57600080fd5b506104516107ec366004615c9f565b61175c565b3480156107fd57600080fd5b5061045161080c366004616182565b611787565b34801561081d57600080fd5b506104f361082c366004616341565b60008281526101c6602090815260408083206001600160a01b038516845260080190915290205460ff1692915050565b34801561086857600080fd5b506105156108773660046160f3565b611808565b34801561088857600080fd5b506104f3610897366004616182565b60016020526000908152604090205460ff1681565b3480156108b857600080fd5b506104516108c7366004616182565b611816565b3480156108d857600080fd5b5061058d611891565b3480156108ed57600080fd5b506104f36108fc366004616182565b6102c16020526000908152604090205460ff1681565b34801561091e57600080fd5b506040805180820190915260018152603160f81b602082015261058d565b34801561094857600080fd5b50610515610957366004616371565b61193e565b34801561096857600080fd5b5061051561097736600461639d565b611967565b34801561098857600080fd5b50610515610997366004615c9f565b6119b1565b3480156109a857600080fd5b506104516109b7366004615c9f565b611a66565b3480156109c857600080fd5b506105156109d7366004616420565b611aee565b3480156109e857600080fd5b506105156109f7366004616479565b611b40565b348015610a0857600080fd5b50610451611c5b565b348015610a1d57600080fd5b50610451611e89565b348015610a3257600080fd5b50610a3b611f1f565b6040516104ca9796959493929190616519565b348015610a5a57600080fd5b50610a63611fbd565b60405165ffffffffffff90911681526020016104ca565b348015610a8657600080fd5b506064610515565b348015610a9a57600080fd5b50610515610aa936600461657b565b612031565b348015610aba57600080fd5b50610515612048565b348015610acf57600080fd5b50610451610ade366004616182565b612075565b348015610aef57600080fd5b50610515610afe366004615c9f565b6120fd565b348015610b0f57600080fd5b50610451610b1e3660046165d3565b612199565b348015610b2f57600080fd5b5060005462010000900460ff166104f3565b348015610b4d57600080fd5b506105156128de565b348015610b6257600080fd5b5061061b610b71366004616632565b63bc197c8160e01b95945050505050565b348015610b8e57600080fd5b50610515610b9d366004615c9f565b6128ea565b348015610bae57600080fd5b506102c2546104f39060ff1681565b610451610bcb3660046166c5565b6128f5565b348015610bdc57600080fd5b50610515610beb3660046160f3565b612a05565b348015610bfc57600080fd5b50610451610c0b366004616708565b612a3f565b348015610c1c57600080fd5b5061022b546001600160a01b03166105d8565b348015610c3b57600080fd5b50610515610c4a366004616731565b612ac7565b348015610c5b57600080fd5b50600054630100000090046001600160a01b03166105d8565b348015610c8057600080fd5b5060408051808201909152601a81527f737570706f72743d627261766f2671756f72756d3d627261766f000000000000602082015261058d565b348015610cc657600080fd5b50610451610cd5366004615c9f565b612b4e565b348015610ce657600080fd5b506105157f150214d74d59b7d1e90c73fc22ef3d991dd0a76b046543d4d80ab92d2a50328f81565b348015610d1a57600080fd5b50610da9610d29366004616341565b60408051606081018252600080825260208201819052918101919091525060009182526101c6602090815260408084206001600160a01b0393909316845260089092018152918190208151606081018352905460ff8082161515835261010082041693820193909352620100009092046001600160601b03169082015290565b6040805182511515815260208084015160ff1690820152918101516001600160601b0316908201526060016104ca565b348015610de557600080fd5b50610451610df4366004615c9f565b612b71565b348015610e0557600080fd5b50610515610e143660046167d2565b612bf9565b348015610e2557600080fd5b50610451610e34366004615c9f565b612c1a565b348015610e4557600080fd5b5061061b610e543660046167fe565b63f23a6e6160e01b95945050505050565b348015610e7157600080fd5b50610515610e80366004615c9f565b612ca2565b348015610e9157600080fd5b506101f8546105d8906001600160a01b031681565b610451610eb4366004615c9f565b612d31565b6000610ece61022b546001600160a01b031690565b905090565b8060008080808080808080610ee78a6120fd565b60008c815261016360205260409020549098506001600160401b03169650610f0e8b6128ea565b60008c81526101c66020526040812080546005820154600683015460078401546001600160a01b039093169e50949a509850929650919450610f4f8d611751565b90506002816007811115610f6557610f65616303565b1493506007816007811115610f7c57610f7c616303565b14925050509193959799509193959799565b6000610f9982612d54565b92915050565b60008061104361103b7fb3b3f3b703cd84ce352197dcff232b1b5d3cfb2025ce47cf04742d0651f1af888c8c8c8c604051610fdb929190616866565b60405180910390208b80519060200120604051602001611020959493929190948552602085019390935260ff9190911660408401526060830152608082015260a00190565b60405160208183030381529060405280519060200120612d79565b868686612da6565b90506110898a828b8b8b8080601f0160208091040260200160405190810160405280939291908181526020018383808284376000920191909152508d9250612dc4915050565b9a9950505050505050505050565b600054630100000090046001600160a01b031633146110c9576040516306fbb1e360e01b815260040160405180910390fd5b60005462010000900460ff166110f257604051636cd6020160e01b815260040160405180910390fd5b6000805462ff0000191681556040517f62451d457bc659158be6e6247f56ec1df424a5c7597f71c20c2bc44e0965c8f99190a1565b61112f610eb9565b6001600160a01b0316336001600160a01b03161461115f5760405162461bcd60e51b815260040161044890616876565b30611168610eb9565b6001600160a01b0316146111a65760008036604051611188929190616866565b604051809103902090505b8061119f610164612e67565b0361119357505b6111af81612ee6565b50565b606061016280546111c2906168ad565b80601f01602080910402602001604051908101604052809291908181526020018280546111ee906168ad565b801561123b5780601f106112105761010080835404028352916020019161123b565b820191906000526020600020905b81548152906001019060200180831161121e57829003601f168201915b5050505050905090565b6000805462010000900460ff161561127057604051631785c68160e01b815260040160405180910390fd5b3360009081526001602052604090205460ff16156112a15760405163b1d02c3d60e01b815260040160405180910390fd5b60005b855181101561131a576102c160008783815181106112c4576112c46168e7565b6020908102919091018101516001600160a01b031682528101919091526040016000205460ff1661130857604051630b094f2760e31b815260040160405180910390fd5b8061131281616913565b9150506112a4565b5061132785858585613057565b95945050505050565b6000610ece600161133f611fbd565b611349919061692c565b65ffffffffffff16612ca2565b60008061136586868686612a05565b9050600061137282611751565b9050600481600781111561138857611388616303565b14806113a5575060058160078111156113a3576113a3616303565b145b6113c15760405162461bcd60e51b815260040161044890616952565b6000828152610163602052604090819020600201805460ff19166001179055517f712ae1383f79ac853f8d882153778e0260ef8f03b504e2866e0593e04d2b291f906114109084815260200190565b60405180910390a1611425828888888861325c565b61143282888888886132fd565b61143f82888888886133df565b5095945050505050565b60608060608060006101c66000878152602001908152602001600020905080600101816002018260030183600401838054806020026020016040519081016040528092919081815260200182805480156114cc57602002820191906000526020600020905b81546001600160a01b031681526001909101906020018083116114ae575b505050505093508280548060200260200160405190810160405280929190818152602001828054801561151e57602002820191906000526020600020905b81548152602001906001019080831161150a575b5050505050925081805480602002602001604051908101604052809291908181526020016000905b828210156115f2578382906000526020600020018054611565906168ad565b80601f0160208091040260200160405190810160405280929190818152602001828054611591906168ad565b80156115de5780601f106115b3576101008083540402835291602001916115de565b820191906000526020600020905b8154815290600101906020018083116115c157829003601f168201915b505050505081526020019060010190611546565b50505050915080805480602002602001604051908101604052809291908181526020016000905b828210156116c5578382906000526020600020018054611638906168ad565b80601f0160208091040260200160405190810160405280929190818152602001828054611664906168ad565b80156116b15780601f10611686576101008083540402835291602001916116b1565b820191906000526020600020905b81548152906001019060200180831161169457829003601f168201915b505050505081526020019060010190611619565b5050505090509450945094509450509193509193565b604080517f150214d74d59b7d1e90c73fc22ef3d991dd0a76b046543d4d80ab92d2a50328f602082015290810186905260ff8516606082015260009081906117299061103b90608001611020565b90506117468782886040518060200160405280600081525061341a565b979650505050505050565b6000610f998261343d565b60008060008061176b8561358a565b935093509350935061177f84848484611808565b505050505050565b600054630100000090046001600160a01b031633146117b9576040516306fbb1e360e01b815260040160405180910390fd5b6001600160a01b0381166000818152600160208190526040808320805460ff1916909217909155517f7fd26be6fc92aff63f1f4409b2b2ddeb272a888031d7f55ec830485ec61941869190a250565b60006113278585858561381b565b600054630100000090046001600160a01b03163314611848576040516306fbb1e360e01b815260040160405180910390fd5b6001600160a01b038116600081815260016020526040808220805460ff19169055517fe0db3499b7fdc3da4cddff5f45d694549c19835e7f719fb5606d3ad1a5de40119190a250565b6101f85460408051634bf5d7e960e01b815290516060926001600160a01b031691634bf5d7e99160048083019260009291908290030181865afa9250505080156118fd57506040513d6000823e601f3d908101601f191682016040526118fa9190810190616993565b60015b611939575060408051808201909152601d81527f6d6f64653d626c6f636b6e756d6265722666726f6d3d64656661756c74000000602082015290565b919050565b60008033905061195f8482856040518060200160405280600081525061341a565b949350505050565b60008033905061174687828888888080601f0160208091040260200160405190810160405280939291908181526020018383808284376000920191909152508a9250612dc4915050565b61025e546000908082036119ca57505061025d54919050565b600061025e6119da600184616a00565b815481106119ea576119ea6168e7565b60009182526020918290206040805180820190915291015463ffffffff8116808352600160201b9091046001600160e01b03169282019290925291508410611a4057602001516001600160e01b03169392505050565b611a55611a4c856138e6565b61025e9061394f565b6001600160e01b0316949350505050565b611a6e610eb9565b6001600160a01b0316336001600160a01b031614611a9e5760405162461bcd60e51b815260040161044890616876565b30611aa7610eb9565b6001600160a01b031614611ae55760008036604051611ac7929190616866565b604051809103902090505b80611ade610164612e67565b03611ad257505b6111af81613a02565b600080339050611b3686828787878080601f01602080910402602001604051908101604052809392919081815260200183838082843760009201919091525061341a92505050565b9695505050505050565b6000805462010000900460ff1615611b6b57604051631785c68160e01b815260040160405180910390fd5b3360009081526001602052604090205460ff1615611b9c5760405163b1d02c3d60e01b815260040160405180910390fd5b611ba4613a45565b3360009081526102c360205260409020548015611c19576000611bc682611751565b90506001816007811115611bdc57611bdc616303565b1480611bf957506000816007811115611bf757611bf7616303565b145b15611c175760405163867f3ee560e01b815260040160405180910390fd5b505b825160208401206000611c2e88888885612a05565b3360009081526102c3602052604090208190559050611c4f88888888613af0565b98975050505050505050565b600054610100900460ff1615808015611c7b5750600054600160ff909116105b80611c955750303b158015611c95575060005460ff166001145b611cf85760405162461bcd60e51b815260206004820152602e60248201527f496e697469616c697a61626c653a20636f6e747261637420697320616c72656160448201526d191e481a5b9a5d1a585b1a5e995960921b6064820152608401610448565b6000805460ff191660011790558015611d1b576000805461ff0019166101001790555b334114611d3b5760405163022d8c9560e31b815260040160405180910390fd5b3a15611d5a576040516383f1b1d360e01b815260040160405180910390fd5b611d866040518060400160405280600b81526020016a2129a1a3b7bb32b93737b960a91b815250613b58565b611db0611d9560036000616a29565b611da160036078616a29565b680ad78ebc5ac6200000613baf565b611db8613be6565b611dc3612005613c0d565b611dce612006613c3d565b611dd8600a613c6d565b611dec611de76003603c616a29565b613c9d565b6110076000526102c16020527f2f832952f0ef896b8c8edd6d16a2e4f2591a90375e33021e3b9ff197f3793fc0805460ff19166001179055611e417304d63abcd2b9b1baa327f2dda0f873f197ccd186613ccd565b80156111af576000805461ff0019169055604051600181527f7f26b83ff96e1f2b6a682f133852f6798a09c465da95921460cefb38474024989060200160405180910390a150565b600054630100000090046001600160a01b03163314611ebb576040516306fbb1e360e01b815260040160405180910390fd5b60005462010000900460ff1615611ee557604051631785c68160e01b815260040160405180910390fd5b6000805462ff00001916620100001781556040517f9e87fac88ff661f02d44f95383c817fece4bce600a3dab7a54406878b965e7529190a1565b6000606080600080600060606098546000801b148015611f3f5750609954155b611f835760405162461bcd60e51b81526020600482015260156024820152741152540dcc4c8e88155b9a5b9a5d1a585b1a5e9959605a1b6044820152606401610448565b611f8b613d20565b611f93613d2f565b60408051600080825260208201909252600f60f81b9b939a50919850469750309650945092509050565b6101f854604080516324776b7d60e21b815290516000926001600160a01b0316916391ddadf49160048083019260209291908290030181865afa925050508015612024575060408051601f3d908101601f1916820190925261202191810190616a4b565b60015b61193957610ece43613d3e565b600061203e848484613da5565b90505b9392505050565b61025e546000901561206d5761205f61025e613e1c565b6001600160e01b0316905090565b5061025d5490565b61207d610eb9565b6001600160a01b0316336001600160a01b0316146120ad5760405162461bcd60e51b815260040161044890616876565b306120b6610eb9565b6001600160a01b0316146120f457600080366040516120d6929190616866565b604051809103902090505b806120ed610164612e67565b036120e157505b6111af81613e4c565b61022b54600082815261022c602052604080822054905163d45c443560e01b81526004810191909152909182916001600160a01b039091169063d45c443590602401602060405180830381865afa15801561215c573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906121809190616a73565b9050806001146121905780612041565b60009392505050565b33611007146121bf57604051630f22c43960e41b81526110076004820152602401610448565b6122256040518060400160405280600b81526020016a766f74696e6744656c617960a81b81525085858080601f0160208091040260200160405190810160405280939291908181526020018383808284376000920191909152509293925050613eb79050565b156122da57602081146122535783838383604051630a5a604160e01b81526004016104489493929190616ab5565b604080516020601f8401819004810282018101909252828152600091612294918585808385018382808284376000920191909152509293925050613f109050565b90508015806122a557506201518081115b156122cb5784848484604051630a5a604160e01b81526004016104489493929190616ab5565b6122d481613a02565b5061289b565b6123416040518060400160405280600c81526020016b1d9bdd1a5b99d4195c9a5bd960a21b81525085858080601f0160208091040260200160405190810160405280939291908181526020018383808284376000920191909152509293925050613eb79050565b156123f0576020811461236f5783838383604051630a5a604160e01b81526004016104489493929190616ab5565b604080516020601f84018190048102820181019092528281526000916123b0918585808385018382808284376000920191909152509293925050613f109050565b90508015806123c1575062278d0081115b156123e75784848484604051630a5a604160e01b81526004016104489493929190616ab5565b6122d481613f15565b61245c604051806040016040528060118152602001701c1c9bdc1bdcd85b151a1c995cda1bdb19607a1b81525085858080601f0160208091040260200160405190810160405280939291908181526020018383808284376000920191909152509293925050613eb79050565b15612512576020811461248a5783838383604051630a5a604160e01b81526004016104489493929190616ab5565b604080516020601f84018190048102820181019092528281526000916124cb918585808385018382808284376000920191909152509293925050613f109050565b90508015806124e3575069021e19e0c9bab240000081115b156125095784848484604051630a5a604160e01b81526004016104489493929190616ab5565b6122d481613fb8565b61257c6040518060400160405280600f81526020016e38bab7b93ab6a73ab6b2b930ba37b960891b81525085858080601f0160208091040260200160405190810160405280939291908181526020018383808284376000920191909152509293925050613eb79050565b1561262b57602081146125aa5783838383604051630a5a604160e01b81526004016104489493929190616ab5565b604080516020601f84018190048102820181019092528281526000916125eb918585808385018382808284376000920191909152509293925050613f109050565b905060058110806125fc5750601481115b156126225784848484604051630a5a604160e01b81526004016104489493929190616ab5565b6122d481612ee6565b61269a604051806040016040528060148152602001736d696e506572696f64416674657251756f72756d60601b81525085858080601f0160208091040260200160405190810160405280939291908181526020018383808284376000920191909152509293925050613eb79050565b1561276057600881146126c85783838383604051630a5a604160e01b81526004016104489493929190616ab5565b600061270e600884848080601f0160208091040260200160405190810160405280939291908181526020018383808284376000920191909152509293925050613f109050565b90506001600160401b038116158061273157506202a300816001600160401b0316115b156127575784848484604051630a5a604160e01b81526004016104489493929190616ab5565b6122d481613ffb565b6127cc6040518060400160405280601181526020017033b7bb32b93737b9283937ba32b1ba37b960791b81525085858080601f0160208091040260200160405190810160405280939291908181526020018383808284376000920191909152509293925050613eb79050565b1561287a57601481146127fa5783838383604051630a5a604160e01b81526004016104489493929190616ab5565b6000612840601484848080601f0160208091040260200160405190810160405280939291908181526020018383808284376000920191909152509293925050613f109050565b90506001600160a01b0381166128715784848484604051630a5a604160e01b81526004016104489493929190616ab5565b6122d481614067565b838383836040516325ee20d560e21b81526004016104489493929190616ab5565b7ff1ce9b2cbf50eeb05769a29e2543fd350cab46894a7dd9978a12d534bb20e633848484846040516128d09493929190616ab5565b60405180910390a150505050565b6000610ece6101965490565b6000610f99826140d3565b6128fd610eb9565b6001600160a01b0316336001600160a01b03161461292d5760405162461bcd60e51b815260040161044890616876565b30612936610eb9565b6001600160a01b0316146129745760008036604051612956929190616866565b604051809103902090505b8061296d610164612e67565b0361296157505b600080856001600160a01b0316858585604051612992929190616866565b60006040518083038185875af1925050503d80600081146129cf576040519150601f19603f3d011682016040523d82523d6000602084013e6129d4565b606091505b50915091506129fc8282604051806060016040528060288152602001616f1260289139614111565b50505050505050565b600084848484604051602001612a1e9493929190616adc565b60408051601f19818403018152919052805160209091012095945050505050565b612a47610eb9565b6001600160a01b0316336001600160a01b031614612a775760405162461bcd60e51b815260040161044890616876565b30612a80610eb9565b6001600160a01b031614612abe5760008036604051612aa0929190616866565b604051809103902090505b80612ab7610164612e67565b03612aab57505b6111af81613ffb565b60008251845114612b2b5760405162461bcd60e51b815260206004820152602860248201527f476f7665726e6f72427261766f3a20696e76616c6964207369676e61747572656044820152670e640d8cadccee8d60c31b6064820152608401610448565b612b3933878787878761412a565b611b368686612b4887876141e8565b85611b40565b600080600080612b5d8561358a565b935093509350935061177f84848484611245565b612b79610eb9565b6001600160a01b0316336001600160a01b031614612ba95760405162461bcd60e51b815260040161044890616876565b30612bb2610eb9565b6001600160a01b031614612bf05760008036604051612bd2929190616866565b604051809103902090505b80612be9610164612e67565b03612bdd57505b6111af81613f15565b60006120418383612c1560408051602081019091526000815290565b613da5565b612c22610eb9565b6001600160a01b0316336001600160a01b031614612c525760405162461bcd60e51b815260040161044890616876565b30612c5b610eb9565b6001600160a01b031614612c995760008036604051612c7b929190616866565b604051809103902090505b80612c92610164612e67565b03612c8657505b6111af81613fb8565b60006064612caf836119b1565b6101f854604051632394e7a360e21b8152600481018690526001600160a01b0390911690638e539e8c90602401602060405180830381865afa158015612cf9573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612d1d9190616a73565b612d279190616b27565b610f999190616a29565b600080600080612d408561358a565b935093509350935061177f84848484611356565b60006001600160e01b03198216636e665ced60e01b1480610f995750610f998261431a565b6000610f99612d866143b6565b8360405161190160f01b8152600281019290925260228201526042902090565b6000806000612db7878787876143c0565b9150915061143f81614484565b6000805462010000900460ff1615612def57604051631785c68160e01b815260040160405180910390fd5b3360009081526001602052604090205460ff1615612e205760405163b1d02c3d60e01b815260040160405180910390fd5b6001600160a01b03851660009081526001602052604090205460ff1615612e5a5760405163b1d02c3d60e01b815260040160405180910390fd5b611b3686868686866145ce565b6000612e828254600f81810b600160801b909204900b131590565b15612ea057604051631ed9509560e11b815260040160405180910390fd5b508054600f0b6000818152600180840160205260408220805492905583546fffffffffffffffffffffffffffffffff191692016001600160801b03169190911790915590565b6064811115612f695760405162461bcd60e51b815260206004820152604360248201527f476f7665726e6f72566f74657351756f72756d4672616374696f6e3a2071756f60448201527f72756d4e756d657261746f72206f7665722071756f72756d44656e6f6d696e616064820152623a37b960e91b608482015260a401610448565b6000612f73612048565b90508015801590612f85575061025e54155b15612fea57604080518082019091526000815261025e9060208101612fa9846146d1565b6001600160e01b039081169091528254600181018455600093845260209384902083519490930151909116600160201b0263ffffffff909316929092179101555b613018613005612ff8611fbd565b65ffffffffffff166138e6565b61300e846146d1565b61025e919061473a565b505060408051828152602081018490527f0553476bf02ef2726e8ce5ced78d63e26e602e4a2257b1f559418e24b4633997910160405180910390a15050565b60008061306686868686612a05565b9050600461307382611751565b600781111561308457613084616303565b146130a15760405162461bcd60e51b815260040161044890616952565b61022b546040805163793d064960e11b815290516000926001600160a01b03169163f27a0c929160048083019260209291908290030181865afa1580156130ec573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906131109190616a73565b61022b5460405163b1c5f42760e01b81529192506001600160a01b03169063b1c5f4279061314b908a908a908a906000908b90600401616b3e565b602060405180830381865afa158015613168573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061318c9190616a73565b600083815261022c60205260408082209290925561022b5491516308f2a0bb60e41b81526001600160a01b0390921691638f2a0bb0916131d9918b918b918b91908b908990600401616b8c565b600060405180830381600087803b1580156131f357600080fd5b505af1158015613207573d6000803e3d6000fd5b505050507f9a2e42fd6722813d69113e7d0079d3d940171428df7373df9c7f7617cfda28928282426132399190616be4565b604080519283526020830191909152015b60405180910390a15095945050505050565b30613265610eb9565b6001600160a01b0316146132f65760005b845181101561177f57306001600160a01b031685828151811061329b5761329b6168e7565b60200260200101516001600160a01b0316036132e6576132e68382815181106132c6576132c66168e7565b60200260200101518051906020012061016461475590919063ffffffff16565b6132ef81616913565b9050613276565b5050505050565b60005462010000900460ff161561332757604051631785c68160e01b815260040160405180910390fd5b3360009081526001602052604090205460ff16156133585760405163b1d02c3d60e01b815260040160405180910390fd5b60005b84518110156133d1576102c1600086838151811061337b5761337b6168e7565b6020908102919091018101516001600160a01b031682528101919091526040016000205460ff166133bf57604051630b094f2760e31b815260040160405180910390fd5b806133c981616913565b91505061335b565b506132f68585858585614791565b306133e8610eb9565b6001600160a01b0316146132f65761016454600f81810b600160801b909204900b13156132f6576000610164556132f6565b60006113278585858561343860408051602081019091526000815290565b612dc4565b60008061344983614806565b9050600481600781111561345f5761345f616303565b1461346a5792915050565b600083815261022c602052604090205480613486575092915050565b61022b54604051632ab0f52960e01b8152600481018390526001600160a01b0390911690632ab0f52990602401602060405180830381865afa1580156134d0573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906134f49190616bf7565b15613503575060079392505050565b61022b54604051632c258a9f60e11b8152600481018390526001600160a01b039091169063584b153e90602401602060405180830381865afa15801561354d573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906135719190616bf7565b15613580575060059392505050565b5060029392505050565b60608060606000806101c660008781526020019081526020016000209050806001018160020161375c83600301805480602002602001604051908101604052809291908181526020016000905b828210156136835783829060005260206000200180546135f6906168ad565b80601f0160208091040260200160405190810160405280929190818152602001828054613622906168ad565b801561366f5780601f106136445761010080835404028352916020019161366f565b820191906000526020600020905b81548152906001019060200180831161365257829003601f168201915b5050505050815260200190600101906135d7565b50505060048601805460408051602080840282018101909252828152935060009084015b828210156137535783829060005260206000200180546136c6906168ad565b80601f01602080910402602001604051908101604052809291908181526020018280546136f2906168ad565b801561373f5780601f106137145761010080835404028352916020019161373f565b820191906000526020600020905b81548152906001019060200180831161372257829003601f168201915b5050505050815260200190600101906136a7565b505050506141e8565b60098401548354604080516020808402820181019092528281529186918301828280156137b257602002820191906000526020600020905b81546001600160a01b03168152600190910190602001808311613794575b505050505093508280548060200260200160405190810160405280929190818152602001828054801561380457602002820191906000526020600020905b8154815260200190600101908083116137f0575b505050505092509450945094509450509193509193565b60008061382a86868686612a05565b60008181526101c660205260409020549091506001600160a01b03163381148061387e57506138576128de565b61387c826001613865611fbd565b61386f919061692c565b65ffffffffffff16612bf9565b105b6138da5760405162461bcd60e51b815260206004820152602760248201527f476f7665726e6f72427261766f3a2070726f706f7365722061626f76652074686044820152661c995cda1bdb1960ca1b6064820152608401610448565b6117468787878761493e565b600063ffffffff82111561394b5760405162461bcd60e51b815260206004820152602660248201527f53616665436173743a2076616c756520646f65736e27742066697420696e203360448201526532206269747360d01b6064820152608401610448565b5090565b8154600090818160058111156139ac57600061396a8461494c565b6139749085616a00565b60008881526020902090915081015463ffffffff908116908716101561399c578091506139aa565b6139a7816001616be4565b92505b505b60006139ba87878585614a34565b905080156139f5576139df876139d1600184616a00565b600091825260209091200190565b54600160201b90046001600160e01b0316611746565b6000979650505050505050565b6101945460408051918252602082018390527fc565b045403dc03c2eea82b81a0465edad9e2e7fc4d97e11421c209da93d7a93910160405180910390a161019455565b6102c25460ff16613aee576a084595161401484a0000006120056001600160a01b03166318160ddd6040518163ffffffff1660e01b8152600401602060405180830381865afa158015613a9c573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613ac09190616a73565b1015613adf576040516311b6707f60e01b815260040160405180910390fd5b6102c2805460ff191660011790555b565b6000613b4c33868686516001600160401b03811115613b1157613b11615d3b565b604051908082528060200260200182016040528015613b4457816020015b6060815260200190600190039081613b2f5790505b50878761412a565b61132785858585614a8a565b600054610100900460ff16613b7f5760405162461bcd60e51b815260040161044890616c19565b613ba681613ba16040805180820190915260018152603160f81b602082015290565b614e69565b6111af81614eb8565b600054610100900460ff16613bd65760405162461bcd60e51b815260040161044890616c19565b613be1838383614ef0565b505050565b600054610100900460ff16613aee5760405162461bcd60e51b815260040161044890616c19565b600054610100900460ff16613c345760405162461bcd60e51b815260040161044890616c19565b6111af81614f32565b600054610100900460ff16613c645760405162461bcd60e51b815260040161044890616c19565b6111af81614f7c565b600054610100900460ff16613c945760405162461bcd60e51b815260040161044890616c19565b6111af81614fa3565b600054610100900460ff16613cc45760405162461bcd60e51b815260040161044890616c19565b6111af81614fca565b600054610100900460ff16613cf45760405162461bcd60e51b815260040161044890616c19565b600080546001600160a01b039092166301000000026301000000600160b81b0319909216919091179055565b6060609a80546111c2906168ad565b6060609b80546111c2906168ad565b600065ffffffffffff82111561394b5760405162461bcd60e51b815260206004820152602660248201527f53616665436173743a2076616c756520646f65736e27742066697420696e203460448201526538206269747360d01b6064820152608401610448565b6101f854604051630748d63560e31b81526001600160a01b038581166004830152602482018590526000921690633a46b1a890604401602060405180830381865afa158015613df8573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061203e9190616a73565b8054600090801561219057613e36836139d1600184616a00565b54600160201b90046001600160e01b0316612041565b61022b54604080516001600160a01b03928316815291831660208301527f08f74ea46ef7894f65eabfb5e6e695de773a000b47c529ab559178069b226401910160405180910390a161022b80546001600160a01b0319166001600160a01b0392909216919091179055565b600081604051602001613eca9190616c64565b6040516020818303038152906040528051906020012083604051602001613ef19190616c64565b6040516020818303038152906040528051906020012014905092915050565b015190565b60008111613f755760405162461bcd60e51b815260206004820152602760248201527f476f7665726e6f7253657474696e67733a20766f74696e6720706572696f6420604482015266746f6f206c6f7760c81b6064820152608401610448565b6101955460408051918252602082018390527f7e3f7f0708a84de9203036abaa450dccc85ad5ff52f78c170f3edb55cf5e8828910160405180910390a161019555565b6101965460408051918252602082018390527fccb45da8d5717e6c4544694297c4ba5cf151d455c9bb0ed4fc7a38411bc05461910160405180910390a161019655565b61028f54604080516001600160401b03928316815291831660208301527f7ca4ac117ed3cdce75c1161d8207c440389b1a15d69d096831664657c07dafc2910160405180910390a161028f805467ffffffffffffffff19166001600160401b0392909216919091179055565b600080546040516001600160a01b0380851693630100000090930416917f44fc1b38a4abaa91ebd1b628a5b259a698f86238c8217d68f516e87769c60c0b91a3600080546001600160a01b039092166301000000026301000000600160b81b0319909216919091179055565b60008181526101636020526040812060010154610f99906001600160401b0316600084815261029060205260409020546001600160401b0316614ff1565b60608315614120575081612041565b6120418383615007565b805160208201206000614148878761414288886141e8565b85612a05565b60008181526101c6602052604090206009810154919250906141dd5780546001600160a01b0319166001600160a01b038a16178155875161419290600183019060208b0190615ad6565b5086516141a890600283019060208a0190615b37565b5085516141be9060038301906020890190615b72565b5084516141d49060048301906020880190615bc4565b50600981018390555b505050505050505050565b6060600082516001600160401b0381111561420557614205615d3b565b60405190808252806020026020018201604052801561423857816020015b60608152602001906001900390816142235790505b50905060005b815181101561431257848181518110614259576142596168e7565b6020026020010151516000146142c95784818151811061427b5761427b6168e7565b60200260200101518051906020012084828151811061429c5761429c6168e7565b60200260200101516040516020016142b5929190616c80565b6040516020818303038152906040526142e4565b8381815181106142db576142db6168e7565b60200260200101515b8282815181106142f6576142f66168e7565b60200260200101819052508061430b90616913565b905061423e565b509392505050565b600063288ace0360e11b6318df743f60e31b63bf26d89760e01b6379dd796f60e01b6001600160e01b0319861682148061436057506001600160e01b0319868116908216145b8061437757506001600160e01b0319868116908516145b8061439257506001600160e01b03198616630271189760e51b145b80611b3657506301ffc9a760e01b6001600160e01b03198716149695505050505050565b6000610ece615031565b6000807f7fffffffffffffffffffffffffffffff5d576e7357a4501ddfe92f46681b20a08311156143f7575060009050600361447b565b6040805160008082526020820180845289905260ff881692820192909252606081018690526080810185905260019060a0016020604051602081039080840390855afa15801561444b573d6000803e3d6000fd5b5050604051601f1901519150506001600160a01b0381166144745760006001925092505061447b565b9150600090505b94509492505050565b600081600481111561449857614498616303565b036144a05750565b60018160048111156144b4576144b4616303565b036145015760405162461bcd60e51b815260206004820152601860248201527f45434453413a20696e76616c6964207369676e617475726500000000000000006044820152606401610448565b600281600481111561451557614515616303565b036145625760405162461bcd60e51b815260206004820152601f60248201527f45434453413a20696e76616c6964207369676e6174757265206c656e677468006044820152606401610448565b600381600481111561457657614576616303565b036111af5760405162461bcd60e51b815260206004820152602260248201527f45434453413a20696e76616c6964207369676e6174757265202773272076616c604482015261756560f01b6064820152608401610448565b6000806145de87878787876150a5565b600088815261029060205260409020549091506001600160401b031615801561460b575061460b876151fb565b15611b3657600061462561028f546001600160401b031690565b61462d611fbd565b65ffffffffffff1661463f9190616cb1565b905061464a886128ea565b816001600160401b03161115614699576040516001600160401b038216815288907f541f725fb9f7c98a30cc9c0ff32fbb14358cd7159c847a3aa20a2bdc442ba5119060200160405180910390a25b600088815261029060205260409020805467ffffffffffffffff19166001600160401b03929092169190911790559695505050505050565b60006001600160e01b0382111561394b5760405162461bcd60e51b815260206004820152602760248201527f53616665436173743a2076616c756520646f65736e27742066697420696e20326044820152663234206269747360c81b6064820152608401610448565b60008061474885858561523b565b915091505b935093915050565b8154600160801b90819004600f0b6000818152600180860160205260409091209390935583546001600160801b03908116939091011602179055565b61022b5460405163e38335e560e01b81526001600160a01b039091169063e38335e59034906147cd908890889088906000908990600401616b3e565b6000604051808303818588803b1580156147e657600080fd5b505af11580156147fa573d6000803e3d6000fd5b50505050505050505050565b600081815261016360205260408120600281015460ff161561482b5750600792915050565b6002810154610100900460ff16156148465750600292915050565b600083815261016360205260408120546001600160401b0316908190036148af5760405162461bcd60e51b815260206004820152601d60248201527f476f7665726e6f723a20756e6b6e6f776e2070726f706f73616c2069640000006044820152606401610448565b60006148b9611fbd565b65ffffffffffff1690508082106148d557506000949350505050565b60006148e0866128ea565b90508181106148f55750600195945050505050565b6148fe866151fb565b8015614921575060008681526101c6602052604090206006810154600590910154115b156149325750600495945050505050565b50600395945050505050565b6000611327858585856153da565b60008160000361495e57506000919050565b6000600161496b84615490565b901c6001901b9050600181848161498457614984616a13565b048201901c9050600181848161499c5761499c616a13565b048201901c905060018184816149b4576149b4616a13565b048201901c905060018184816149cc576149cc616a13565b048201901c905060018184816149e4576149e4616a13565b048201901c905060018184816149fc576149fc616a13565b048201901c90506001818481614a1457614a14616a13565b048201901c905061204181828581614a2e57614a2e616a13565b04615524565b60005b81831015614312576000614a4b8484615533565b60008781526020902090915063ffffffff86169082015463ffffffff161115614a7657809250614a84565b614a81816001616be4565b93505b50614a37565b600033614a97818461554e565b614ae35760405162461bcd60e51b815260206004820152601d60248201527f476f7665726e6f723a2070726f706f73657220726573747269637465640000006044820152606401610448565b6000614aed611fbd565b65ffffffffffff169050614aff6128de565b614b0e83610e14600185616a00565b1015614b765760405162461bcd60e51b815260206004820152603160248201527f476f7665726e6f723a2070726f706f73657220766f7465732062656c6f7720706044820152701c9bdc1bdcd85b081d1a1c995cda1bdb19607a1b6064820152608401610448565b6000614b8b8888888880519060200120612a05565b90508651885114614bae5760405162461bcd60e51b815260040161044890616cd1565b8551885114614bcf5760405162461bcd60e51b815260040161044890616cd1565b6000885111614c205760405162461bcd60e51b815260206004820152601860248201527f476f7665726e6f723a20656d7074792070726f706f73616c00000000000000006044820152606401610448565b600081815261016360205260409020546001600160401b031615614c905760405162461bcd60e51b815260206004820152602160248201527f476f7665726e6f723a2070726f706f73616c20616c72656164792065786973746044820152607360f81b6064820152608401610448565b6000614c9c6101945490565b614ca69084616be4565b90506000614cb46101955490565b614cbe9083616be4565b90506040518060e00160405280614cd48461563f565b6001600160401b031681526001600160a01b038716602082015260006040820152606001614d018361563f565b6001600160401b03908116825260006020808401829052604080850183905260609485018390528883526101638252918290208551815492870151878501519186166001600160e01b031990941693909317600160401b6001600160a01b039094168402176001600160e01b0316600160e01b60e09290921c91909102178155938501516080860151908416921c0217600183015560a08301516002909201805460c09094015161ffff1990941692151561ff00191692909217610100931515939093029290921790558a517f7d84a6263ae0d98d3329bd7b46bb4e8d6f98cd35a7adb45c274c8b7fd5ebd5e091859188918e918e91811115614e0657614e06615d3b565b604051908082528060200260200182016040528015614e3957816020015b6060815260200190600190039081614e245790505b508d88888f604051614e5399989796959493929190616d12565b60405180910390a1509098975050505050505050565b600054610100900460ff16614e905760405162461bcd60e51b815260040161044890616c19565b609a614e9c8382616df0565b50609b614ea98282616df0565b50506000609881905560995550565b600054610100900460ff16614edf5760405162461bcd60e51b815260040161044890616c19565b610162614eec8282616df0565b5050565b600054610100900460ff16614f175760405162461bcd60e51b815260040161044890616c19565b614f2083613a02565b614f2982613f15565b613be181613fb8565b600054610100900460ff16614f595760405162461bcd60e51b815260040161044890616c19565b6101f880546001600160a01b0319166001600160a01b0392909216919091179055565b600054610100900460ff166120f45760405162461bcd60e51b815260040161044890616c19565b600054610100900460ff166111a65760405162461bcd60e51b815260040161044890616c19565b600054610100900460ff16612abe5760405162461bcd60e51b815260040161044890616c19565b60008183116150005781612041565b5090919050565b8151156150175781518083602001fd5b8060405162461bcd60e51b81526004016104489190615ef4565b60007f8b73c3c69bb8fe3d512ecc4cf759cc79239f7b179b0ffacaa9a75d522b39400f61505c6156a7565b615064615700565b60408051602081019490945283019190915260608201524660808201523060a082015260c00160405160208183030381529060405280519060200120905090565b60008581526101636020526040812060016150bf88611751565b60078111156150d0576150d0616303565b146151295760405162461bcd60e51b815260206004820152602360248201527f476f7665726e6f723a20766f7465206e6f742063757272656e746c792061637460448201526269766560e81b6064820152608401610448565b80546000906151439088906001600160401b031686613da5565b90506151528888888488615731565b83516000036151a757866001600160a01b03167fb8e138887d0aa13bab447e82de9d5c1777041ecd21ca36ba824ff1e6c07ddda48988848960405161519a9493929190616eaf565b60405180910390a2611746565b866001600160a01b03167fe2babfbac5889a709b63bb7f598b324e08bc5a4fb9ec647fb3cbc9ec07eb871289888489896040516151e8959493929190616ed7565b60405180910390a2979650505050505050565b60008181526101c6602052604081206005810154615232610e8085600090815261016360205260409020546001600160401b031690565b11159392505050565b825460009081908015615381576000615259876139d1600185616a00565b60408051808201909152905463ffffffff808216808452600160201b9092046001600160e01b0316602084015291925090871610156152da5760405162461bcd60e51b815260206004820152601b60248201527f436865636b706f696e743a2064656372656173696e67206b65797300000000006044820152606401610448565b805163ffffffff80881691160361532257846152fb886139d1600186616a00565b80546001600160e01b0392909216600160201b0263ffffffff909216919091179055615371565b6040805180820190915263ffffffff80881682526001600160e01b0380881660208085019182528b54600181018d5560008d81529190912094519151909216600160201b029216919091179101555b60200151925083915061474d9050565b50506040805180820190915263ffffffff80851682526001600160e01b0380851660208085019182528854600181018a5560008a815291822095519251909316600160201b02919093161792019190915590508161474d565b6000806153e9868686866158cf565b600081815261022c6020526040902054909150156113275761022b54600082815261022c60205260409081902054905163c4d252f560e01b81526001600160a01b039092169163c4d252f5916154459160040190815260200190565b600060405180830381600087803b15801561545f57600080fd5b505af1158015615473573d6000803e3d6000fd5b505050600082815261022c60205260408120555095945050505050565b600080608083901c156154a557608092831c92015b604083901c156154b757604092831c92015b602083901c156154c957602092831c92015b601083901c156154db57601092831c92015b600883901c156154ed57600892831c92015b600483901c156154ff57600492831c92015b600283901c1561551157600292831c92015b600183901c15610f995760010192915050565b60008183106150005781612041565b60006155426002848418616a29565b61204190848416616be4565b80516000906034811015615566576001915050610f99565b82810160131901516001600160a01b031981166b046e0e4dee0dee6cae47a60f60a31b1461559957600192505050610f99565b6000806155a7602885616a00565b90505b8381101561561e576000806155de8884815181106155ca576155ca6168e7565b01602001516001600160f81b0319166159dc565b91509150816155f65760019650505050505050610f99565b8060ff166004856001600160a01b0316901b17935050508061561790616913565b90506155aa565b50856001600160a01b0316816001600160a01b031614935050505092915050565b60006001600160401b0382111561394b5760405162461bcd60e51b815260206004820152602660248201527f53616665436173743a2076616c756520646f65736e27742066697420696e203660448201526534206269747360d01b6064820152608401610448565b6000806156b2613d20565b8051909150156156c9578051602090910120919050565b60985480156156d85792915050565b7fc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a4709250505090565b60008061570b613d2f565b805190915015615722578051602090910120919050565b60995480156156d85792915050565b60008581526101c6602090815260408083206001600160a01b038816845260088101909252909120805460ff16156157c15760405162461bcd60e51b815260206004820152602d60248201527f476f7665726e6f72436f6d7061746962696c697479427261766f3a20766f746560448201526c08185b1c9958591e4818d85cdd609a1b6064820152608401610448565b805460ff86166101000261ffff199091161760011781556157e184615a6e565b81546001600160601b039190911662010000026dffffffffffffffffffffffff00001990911617815560ff851661583157838260060160008282546158269190616be4565b909155506129fc9050565b60001960ff86160161585157838260050160008282546158269190616be4565b60011960ff86160161587157838260070160008282546158269190616be4565b60405162461bcd60e51b815260206004820152602d60248201527f476f7665726e6f72436f6d7061746962696c697479427261766f3a20696e766160448201526c6c696420766f7465207479706560981b6064820152608401610448565b6000806158de86868686612a05565b905060006158eb82611751565b9050600281600781111561590157615901616303565b141580156159215750600681600781111561591e5761591e616303565b14155b801561593f5750600781600781111561593c5761593c616303565b14155b61598b5760405162461bcd60e51b815260206004820152601d60248201527f476f7665726e6f723a2070726f706f73616c206e6f74206163746976650000006044820152606401610448565b6000828152610163602052604090819020600201805461ff001916610100179055517f789cf55be980739dad1d0699b93b58e806b51c9d96619bfa8fe0a28abaa7b30c9061324a9084815260200190565b60008060f883901c602f811180156159f75750603a8160ff16105b15615a0c57600194602f199091019350915050565b8060ff166040108015615a22575060478160ff16105b15615a37576001946036199091019350915050565b8060ff166060108015615a4d575060678160ff16105b15615a62576001946056199091019350915050565b50600093849350915050565b60006001600160601b0382111561394b5760405162461bcd60e51b815260206004820152602660248201527f53616665436173743a2076616c756520646f65736e27742066697420696e203960448201526536206269747360d01b6064820152608401610448565b828054828255906000526020600020908101928215615b2b579160200282015b82811115615b2b57825182546001600160a01b0319166001600160a01b03909116178255602090920191600190910190615af6565b5061394b929150615c16565b828054828255906000526020600020908101928215615b2b579160200282015b82811115615b2b578251825591602001919060010190615b57565b828054828255906000526020600020908101928215615bb8579160200282015b82811115615bb85782518290615ba89082616df0565b5091602001919060010190615b92565b5061394b929150615c2b565b828054828255906000526020600020908101928215615c0a579160200282015b82811115615c0a5782518290615bfa9082616df0565b5091602001919060010190615be4565b5061394b929150615c48565b5b8082111561394b5760008155600101615c17565b8082111561394b576000615c3f8282615c65565b50600101615c2b565b8082111561394b576000615c5c8282615c65565b50600101615c48565b508054615c71906168ad565b6000825580601f10615c81575050565b601f0160209004906000526020600020908101906111af9190615c16565b600060208284031215615cb157600080fd5b5035919050565b600060208284031215615cca57600080fd5b81356001600160e01b03198116811461204157600080fd5b803560ff8116811461193957600080fd5b60008083601f840112615d0557600080fd5b5081356001600160401b03811115615d1c57600080fd5b602083019150836020828501011115615d3457600080fd5b9250929050565b634e487b7160e01b600052604160045260246000fd5b604051601f8201601f191681016001600160401b0381118282101715615d7957615d79615d3b565b604052919050565b60006001600160401b03821115615d9a57615d9a615d3b565b50601f01601f191660200190565b600082601f830112615db957600080fd5b8135615dcc615dc782615d81565b615d51565b818152846020838601011115615de157600080fd5b816020850160208301376000918101602001919091529392505050565b60008060008060008060008060e0898b031215615e1a57600080fd5b88359750615e2a60208a01615ce2565b965060408901356001600160401b0380821115615e4657600080fd5b615e528c838d01615cf3565b909850965060608b0135915080821115615e6b57600080fd5b50615e788b828c01615da8565b945050615e8760808a01615ce2565b925060a0890135915060c089013590509295985092959890939650565b60005b83811015615ebf578181015183820152602001615ea7565b50506000910152565b60008151808452615ee0816020860160208601615ea4565b601f01601f19169290920160200192915050565b6020815260006120416020830184615ec8565b6001600160a01b03811681146111af57600080fd5b60008060008060808587031215615f3257600080fd5b8435615f3d81615f07565b93506020850135615f4d81615f07565b92506040850135915060608501356001600160401b03811115615f6f57600080fd5b615f7b87828801615da8565b91505092959194509250565b60006001600160401b03821115615fa057615fa0615d3b565b5060051b60200190565b600082601f830112615fbb57600080fd5b81356020615fcb615dc783615f87565b82815260059290921b84018101918181019086841115615fea57600080fd5b8286015b8481101561600e57803561600181615f07565b8352918301918301615fee565b509695505050505050565b600082601f83011261602a57600080fd5b8135602061603a615dc783615f87565b82815260059290921b8401810191818101908684111561605957600080fd5b8286015b8481101561600e578035835291830191830161605d565b600082601f83011261608557600080fd5b81356020616095615dc783615f87565b82815260059290921b840181019181810190868411156160b457600080fd5b8286015b8481101561600e5780356001600160401b038111156160d75760008081fd5b6160e58986838b0101615da8565b8452509183019183016160b8565b6000806000806080858703121561610957600080fd5b84356001600160401b038082111561612057600080fd5b61612c88838901615faa565b9550602087013591508082111561614257600080fd5b61614e88838901616019565b9450604087013591508082111561616457600080fd5b5061617187828801616074565b949793965093946060013593505050565b60006020828403121561619457600080fd5b813561204181615f07565b600081518084526020808501945080840160005b838110156161d85781516001600160a01b0316875295820195908201906001016161b3565b509495945050505050565b600081518084526020808501945080840160005b838110156161d8578151875295820195908201906001016161f7565b600081518084526020808501808196508360051b8101915082860160005b8581101561625b578284038952616249848351615ec8565b98850198935090840190600101616231565b5091979650505050505050565b60808152600061627b608083018761619f565b828103602084015261628d81876161e3565b905082810360408401526162a18186616213565b905082810360608401526117468185616213565b600080600080600060a086880312156162cd57600080fd5b853594506162dd60208701615ce2565b93506162eb60408701615ce2565b94979396509394606081013594506080013592915050565b634e487b7160e01b600052602160045260246000fd5b602081016008831061633b57634e487b7160e01b600052602160045260246000fd5b91905290565b6000806040838503121561635457600080fd5b82359150602083013561636681615f07565b809150509250929050565b6000806040838503121561638457600080fd5b8235915061639460208401615ce2565b90509250929050565b6000806000806000608086880312156163b557600080fd5b853594506163c560208701615ce2565b935060408601356001600160401b03808211156163e157600080fd5b6163ed89838a01615cf3565b9095509350606088013591508082111561640657600080fd5b5061641388828901615da8565b9150509295509295909350565b6000806000806060858703121561643657600080fd5b8435935061644660208601615ce2565b925060408501356001600160401b0381111561646157600080fd5b61646d87828801615cf3565b95989497509550505050565b6000806000806080858703121561648f57600080fd5b84356001600160401b03808211156164a657600080fd5b6164b288838901615faa565b955060208701359150808211156164c857600080fd5b6164d488838901616019565b945060408701359150808211156164ea57600080fd5b6164f688838901616074565b9350606087013591508082111561650c57600080fd5b50615f7b87828801615da8565b60ff60f81b8816815260e06020820152600061653860e0830189615ec8565b828103604084015261654a8189615ec8565b606084018890526001600160a01b038716608085015260a0840186905283810360c0850152905061108981856161e3565b60008060006060848603121561659057600080fd5b833561659b81615f07565b92506020840135915060408401356001600160401b038111156165bd57600080fd5b6165c986828701615da8565b9150509250925092565b600080600080604085870312156165e957600080fd5b84356001600160401b038082111561660057600080fd5b61660c88838901615cf3565b9096509450602087013591508082111561662557600080fd5b5061646d87828801615cf3565b600080600080600060a0868803121561664a57600080fd5b853561665581615f07565b9450602086013561666581615f07565b935060408601356001600160401b038082111561668157600080fd5b61668d89838a01616019565b945060608801359150808211156166a357600080fd5b6166af89838a01616019565b9350608088013591508082111561640657600080fd5b600080600080606085870312156166db57600080fd5b84356166e681615f07565b93506020850135925060408501356001600160401b0381111561646157600080fd5b60006020828403121561671a57600080fd5b81356001600160401b038116811461204157600080fd5b600080600080600060a0868803121561674957600080fd5b85356001600160401b038082111561676057600080fd5b61676c89838a01615faa565b9650602088013591508082111561678257600080fd5b61678e89838a01616019565b955060408801359150808211156167a457600080fd5b6167b089838a01616074565b945060608801359150808211156167c657600080fd5b6166af89838a01616074565b600080604083850312156167e557600080fd5b82356167f081615f07565b946020939093013593505050565b600080600080600060a0868803121561681657600080fd5b853561682181615f07565b9450602086013561683181615f07565b9350604086013592506060860135915060808601356001600160401b0381111561685a57600080fd5b61641388828901615da8565b8183823760009101908152919050565b60208082526018908201527f476f7665726e6f723a206f6e6c79476f7665726e616e63650000000000000000604082015260600190565b600181811c908216806168c157607f821691505b6020821081036168e157634e487b7160e01b600052602260045260246000fd5b50919050565b634e487b7160e01b600052603260045260246000fd5b634e487b7160e01b600052601160045260246000fd5b600060018201616925576169256168fd565b5060010190565b65ffffffffffff82811682821603908082111561694b5761694b6168fd565b5092915050565b60208082526021908201527f476f7665726e6f723a2070726f706f73616c206e6f74207375636365737366756040820152601b60fa1b606082015260800190565b6000602082840312156169a557600080fd5b81516001600160401b038111156169bb57600080fd5b8201601f810184136169cc57600080fd5b80516169da615dc782615d81565b8181528560208385010111156169ef57600080fd5b611327826020830160208601615ea4565b81810381811115610f9957610f996168fd565b634e487b7160e01b600052601260045260246000fd5b600082616a4657634e487b7160e01b600052601260045260246000fd5b500490565b600060208284031215616a5d57600080fd5b815165ffffffffffff8116811461204157600080fd5b600060208284031215616a8557600080fd5b5051919050565b81835281816020850137506000828201602090810191909152601f909101601f19169091010190565b604081526000616ac9604083018688616a8c565b8281036020840152611746818587616a8c565b608081526000616aef608083018761619f565b8281036020840152616b0181876161e3565b90508281036040840152616b158186616213565b91505082606083015295945050505050565b8082028115828204841417610f9957610f996168fd565b60a081526000616b5160a083018861619f565b8281036020840152616b6381886161e3565b90508281036040840152616b778187616213565b60608401959095525050608001529392505050565b60c081526000616b9f60c083018961619f565b8281036020840152616bb181896161e3565b90508281036040840152616bc58188616213565b60608401969096525050608081019290925260a0909101529392505050565b80820180821115610f9957610f996168fd565b600060208284031215616c0957600080fd5b8151801515811461204157600080fd5b6020808252602b908201527f496e697469616c697a61626c653a20636f6e7472616374206973206e6f74206960408201526a6e697469616c697a696e6760a81b606082015260800190565b60008251616c76818460208701615ea4565b9190910192915050565b6001600160e01b0319831681528151600090616ca3816004850160208701615ea4565b919091016004019392505050565b6001600160401b0381811683821601908082111561694b5761694b6168fd565b60208082526021908201527f476f7665726e6f723a20696e76616c69642070726f706f73616c206c656e67746040820152600d60fb1b606082015260800190565b8981526001600160a01b038916602082015261012060408201819052600090616d3d8382018b61619f565b90508281036060840152616d51818a6161e3565b90508281036080840152616d658189616213565b905082810360a0840152616d798188616213565b90508560c08401528460e0840152828103610100840152616d9a8185615ec8565b9c9b505050505050505050505050565b601f821115613be157600081815260208120601f850160051c81016020861015616dd15750805b601f850160051c820191505b8181101561177f57828155600101616ddd565b81516001600160401b03811115616e0957616e09615d3b565b616e1d81616e1784546168ad565b84616daa565b602080601f831160018114616e525760008415616e3a5750858301515b600019600386901b1c1916600185901b17855561177f565b600085815260208120601f198616915b82811015616e8157888601518255948401946001909101908401616e62565b5085821015616e9f5787850151600019600388901b60f8161c191681555b5050505050600190811b01905550565b84815260ff84166020820152826040820152608060608201526000611b366080830184615ec8565b85815260ff8516602082015283604082015260a060608201526000616eff60a0830185615ec8565b8281036080840152611c4f8185615ec856fe476f7665726e6f723a2072656c617920726576657274656420776974686f7574206d657373616765a164736f6c6343000811000a \ No newline at end of file diff --git a/core/systemcontracts/pasteur/rialto/StakeHubContract b/core/systemcontracts/pasteur/rialto/StakeHubContract new file mode 100644 index 0000000000..da3f8cc6f2 --- /dev/null +++ b/core/systemcontracts/pasteur/rialto/StakeHubContract @@ -0,0 +1 @@ +6080604052600436106200043b5760003560e01c806386d545061162000233578063ca47908f116200012f578063dd42a1dd11620000b9578063f1f74d841162000084578063f1f74d841462000d74578063f80a34021462000d8c578063fb50b31f1462000db1578063fc0c5ff11462000dd6578063ff69ab611462000dee57600080fd5b8063dd42a1dd1462000ce1578063e8f67c3b1462000d08578063e992aaf51462000d20578063efdbf0e11462000d3857600080fd5b8063d7c2dfc811620000fa578063d7c2dfc81462000c67578063d8ca511f1462000c8c578063daacdb661462000ca4578063dbda7fb31462000cbc57600080fd5b8063ca47908f1462000bd0578063cbb04d9d1462000be8578063d115a2061462000c29578063d6ca429d1462000c4257600080fd5b8063b187bd2611620001bd578063bfff04751162000188578063bfff04751462000b57578063c166f58a1462000b7c578063c38fbec81462000b93578063c473318f1462000bb8578063c8509d81146200095057600080fd5b8063b187bd261462000ac4578063baa7199e1462000ae4578063bdceadf31462000b09578063bff02e201462000b2157600080fd5b8063a1832e6411620001fe578063a1832e641462000a21578063a43569b31462000a46578063aad3ec961462000a7a578063ac4317511462000a9f57600080fd5b806386d54506146200098d5780638a4d3fa814620009c75780638cd22b2214620009e5578063982ef0a71462000a0a57600080fd5b80634838d165116200034357806364028fbd11620002cd57806375cc7d89116200029857806375cc7d8914620008fb57806376e7d6d614620009205780638129fc1c1462000938578063831d65d114620009505780638456cb59146200097557600080fd5b806364028fbd1462000836578063663706d3146200084d5780636ec01b27146200087e5780636f8e2fa414620008d657600080fd5b80634e6fd6c4116200030e5780634e6fd6c4146200079d5780635949187114620007b55780635e7cc1c914620007da57806363a036b514620007ff57600080fd5b80634838d16514620006e957806349f41a42146200072e5780634a49ac4c14620007535780634d99dd16146200077857600080fd5b80631fab701511620003c5578063384099881162000390578063384099881462000662578063417c73a7146200067a578063449ecfe6146200069f57806345211bfd14620006c457600080fd5b80631fab701514620005a95780632b727c8614620005ce5780632e8e8c7114620005f3578063367dad49146200062d57600080fd5b80630e9fbf5111620004065780630e9fbf5114620004f35780631182b875146200051857806317b4f353146200054c5780631fa8882b146200059157600080fd5b8063046f7da2146200045b578063059ddd2214620004735780630661806e14620004b5578063092193ab14620004dc57600080fd5b36620004565760345460ff166001146200045457600080fd5b005b600080fd5b3480156200046857600080fd5b506200045462000e06565b3480156200048057600080fd5b506200049862000492366004620097c0565b62000e98565b6040516001600160a01b0390911681526020015b60405180910390f35b348015620004c257600080fd5b50620004cd60365481565b604051908152602001620004ac565b62000454620004ed366004620097c0565b620012c0565b3480156200050057600080fd5b50620004546200051236600462009822565b62001911565b3480156200052557600080fd5b506200053d6200053736600462009867565b62001c9b565b604051620004ac91906200991a565b3480156200055957600080fd5b50620004986200056b366004620099ec565b80516020818301810180516045825292820191909301209152546001600160a01b031681565b3480156200059e57600080fd5b50620004cd61025881565b348015620005b657600080fd5b5062000454620005c836600462009a88565b62001d33565b348015620005db57600080fd5b5062000498620005ed366004620097c0565b6200208a565b3480156200060057600080fd5b506200049862000612366004620097c0565b604d602052600090815260409020546001600160a01b031681565b3480156200063a57600080fd5b50620006526200064c36600462009a88565b620020df565b604051620004ac92919062009b07565b3480156200066f57600080fd5b50620004cd60375481565b3480156200068757600080fd5b506200045462000699366004620097c0565b620026ae565b348015620006ac57600080fd5b5062000454620006be366004620097c0565b62002730565b348015620006d157600080fd5b5062000454620006e3366004620097c0565b62002915565b348015620006f657600080fd5b506200071d62000708366004620097c0565b60016020526000908152604090205460ff1681565b6040519015158152602001620004ac565b3480156200073b57600080fd5b50620004546200074d366004620097c0565b62002aed565b3480156200076057600080fd5b506200045462000772366004620097c0565b62002d09565b3480156200078557600080fd5b50620004546200079736600462009ba6565b62002d85565b348015620007aa57600080fd5b506200049861dead81565b348015620007c257600080fd5b5062000454620007d436600462009be4565b620033b5565b348015620007e757600080fd5b5062000454620007f936600462009c4e565b620041ae565b3480156200080c57600080fd5b50620008246200081e36600462009c75565b620043d7565b604051620004ac949392919062009c98565b620004546200084736600462009d54565b62004a7c565b3480156200085a57600080fd5b50620004cd6200086c366004620097c0565b60446020526000908152604090205481565b3480156200088b57600080fd5b50620008a36200089d366004620097c0565b620050cb565b6040805182516001600160401b0390811682526020808501518216908301529282015190921690820152606001620004ac565b348015620008e357600080fd5b506200053d620008f5366004620097c0565b62005170565b3480156200090857600080fd5b50620004546200091a366004620097c0565b6200559c565b3480156200092d57600080fd5b50620004cd603d5481565b3480156200094557600080fd5b50620004546200576e565b3480156200095d57600080fd5b50620004546200096f36600462009867565b62005936565b3480156200098257600080fd5b506200045462005994565b3480156200099a57600080fd5b5062000498620009ac366004620097c0565b6043602052600090815260409020546001600160a01b031681565b348015620009d457600080fd5b50620004cd670de0b6b3a764000081565b348015620009f257600080fd5b50620004cd62000a0436600462009ba6565b62005a2c565b6200045462000a1b36600462009e2a565b62005ae5565b34801562000a2e57600080fd5b506200045462000a4036600462009a88565b62006193565b34801562000a5357600080fd5b5062000a6b62000a65366004620097c0565b62006499565b604051620004ac919062009e62565b34801562000a8757600080fd5b506200045462000a9936600462009ba6565b62006786565b34801562000aac57600080fd5b506200045462000abe36600462009edf565b620067f3565b34801562000ad157600080fd5b5060005462010000900460ff166200071d565b34801562000af157600080fd5b506200045462000b0336600462009f51565b620077a5565b34801562000b1657600080fd5b50620004cd603c5481565b34801562000b2e57600080fd5b5062000b4662000b4036600462009c75565b62007972565b604051620004ac9392919062009faa565b34801562000b6457600080fd5b50620004cd62000b76366004620097c0565b62007b4e565b34801562000b8957600080fd5b50620004cd600581565b34801562000ba057600080fd5b506200045462000bb2366004620097c0565b62007b9c565b34801562000bc557600080fd5b50620004cd60385481565b34801562000bdd57600080fd5b50620004cd604e5481565b34801562000bf557600080fd5b5062000c0d62000c07366004620097c0565b62007ebc565b60408051938452911515602084015290820152606001620004ac565b34801562000c3657600080fd5b50620004cd620186a081565b34801562000c4f57600080fd5b506200045462000c613660046200a007565b620082ff565b34801562000c7457600080fd5b506200045462000c863660046200a0f0565b62008524565b34801562000c9957600080fd5b50620004cd603b5481565b34801562000cb157600080fd5b50620004cd60495481565b34801562000cc957600080fd5b506200049862000cdb366004620097c0565b6200861a565b34801562000cee57600080fd5b50600054630100000090046001600160a01b031662000498565b34801562000d1557600080fd5b50620004cd60355481565b34801562000d2d57600080fd5b50620004cd603a5481565b34801562000d4557600080fd5b50620004cd62000d57366004620099ec565b805160208183018101805160468252928201919093012091525481565b34801562000d8157600080fd5b50620004cd603e5481565b34801562000d9957600080fd5b50620004cd62000dab36600462009ba6565b62008a44565b34801562000dbe57600080fd5b506200045462000dd036600462009edf565b62008ab5565b34801562000de357600080fd5b50620004cd60395481565b34801562000dfb57600080fd5b50620004cd604a5481565b600054630100000090046001600160a01b0316331462000e39576040516306fbb1e360e01b815260040160405180910390fd5b60005462010000900460ff1662000e6357604051636cd6020160e01b815260040160405180910390fd5b6000805462ff0000191681556040517f62451d457bc659158be6e6247f56ec1df424a5c7597f71c20c2bc44e0965c8f99190a1565b6001600160a01b038082166000908152604160209081526040808320815161018081018352815486168152600182015486169381019390935260028101549094169082015260038301546060820152600483018054929384939091608084019162000f03906200a156565b80601f016020809104026020016040519081016040528092919081815260200182805462000f31906200a156565b801562000f825780601f1062000f565761010080835404028352916020019162000f82565b820191906000526020600020905b81548152906001019060200180831162000f6457829003601f168201915b505050505081526020016005820160405180608001604052908160008201805462000fad906200a156565b80601f016020809104026020016040519081016040528092919081815260200182805462000fdb906200a156565b80156200102c5780601f1062001000576101008083540402835291602001916200102c565b820191906000526020600020905b8154815290600101906020018083116200100e57829003601f168201915b5050505050815260200160018201805462001047906200a156565b80601f016020809104026020016040519081016040528092919081815260200182805462001075906200a156565b8015620010c65780601f106200109a57610100808354040283529160200191620010c6565b820191906000526020600020905b815481529060010190602001808311620010a857829003601f168201915b50505050508152602001600282018054620010e1906200a156565b80601f01602080910402602001604051908101604052809291908181526020018280546200110f906200a156565b8015620011605780601f10620011345761010080835404028352916020019162001160565b820191906000526020600020905b8154815290600101906020018083116200114257829003601f168201915b505050505081526020016003820180546200117b906200a156565b80601f0160208091040260200160405190810160405280929190818152602001828054620011a9906200a156565b8015620011fa5780601f10620011ce57610100808354040283529160200191620011fa565b820191906000526020600020905b815481529060010190602001808311620011dc57829003601f168201915b505050919092525050508152604080516060808201835260098501546001600160401b038082168452600160401b82048116602080860191909152600160801b9092041683850152840191909152600a84015460ff16151582840152600b84015490830152600c8301546080830152600d8301546001600160a01b031660a0830152805161026081019182905260c09092019190600e84019060139082845b81548152602001906001019080831162001299575050509190925250509051949350505050565b3361100014620012ec57604051630f22c43960e41b815261100060048201526024015b60405180910390fd5b6001600160a01b0380821660009081526043602090815260408083205484168084526041835281842082516101808101845281548716815260018201548716948101949094526002810154909516918301919091526003840154606083015260048401805491949160808401919062001365906200a156565b80601f016020809104026020016040519081016040528092919081815260200182805462001393906200a156565b8015620013e45780601f10620013b857610100808354040283529160200191620013e4565b820191906000526020600020905b815481529060010190602001808311620013c657829003601f168201915b50505050508152602001600582016040518060800160405290816000820180546200140f906200a156565b80601f01602080910402602001604051908101604052809291908181526020018280546200143d906200a156565b80156200148e5780601f1062001462576101008083540402835291602001916200148e565b820191906000526020600020905b8154815290600101906020018083116200147057829003601f168201915b50505050508152602001600182018054620014a9906200a156565b80601f0160208091040260200160405190810160405280929190818152602001828054620014d7906200a156565b8015620015285780601f10620014fc5761010080835404028352916020019162001528565b820191906000526020600020905b8154815290600101906020018083116200150a57829003601f168201915b5050505050815260200160028201805462001543906200a156565b80601f016020809104026020016040519081016040528092919081815260200182805462001571906200a156565b8015620015c25780601f106200159657610100808354040283529160200191620015c2565b820191906000526020600020905b815481529060010190602001808311620015a457829003601f168201915b50505050508152602001600382018054620015dd906200a156565b80601f01602080910402602001604051908101604052809291908181526020018280546200160b906200a156565b80156200165c5780601f1062001630576101008083540402835291602001916200165c565b820191906000526020600020905b8154815290600101906020018083116200163e57829003601f168201915b505050919092525050508152604080516060808201835260098501546001600160401b038082168452600160401b82048116602080860191909152600160801b9092041683850152840191909152600a84015460ff16151582840152600b84015490830152600c8301546080830152600d8301546001600160a01b031660a0830152805161026081019182905260c09092019190600e84019060139082845b815481526020019060010190808311620016fb575050509190925250505060408101519091506001600160a01b031615806200173857508060e001515b15620017f557604051611002903490600081818185875af1925050503d806000811462001782576040519150601f19603f3d011682016040523d82523d6000602084013e62001787565b606091505b505050816001600160a01b03167ffc8bff675087dd2da069cc3fb517b9ed001e19750c0865241a5542dba1ba170d604051620017e89060208082526011908201527024a72b20a624a22fab20a624a220aa27a960791b604082015260600190565b60405180910390a2505050565b60408181015160c0830151519151632f303ebb60e11b81526001600160401b0390921660048301526001600160a01b031690635e607d769034906024016000604051808303818588803b1580156200184c57600080fd5b505af115801562001861573d6000803e3d6000fd5b5050505050816001600160a01b03167fe34918ff1c7084970068b53fd71ad6d8b04e9f15d3886cbf006443e6cdc52ea634604051620018a291815260200190565b60405180910390a26040808201519051633041949b60e01b815261200591633041949b91620018d7919086906004016200a18c565b600060405180830381600087803b158015620018f257600080fd5b505af115801562001907573d6000803e3d6000fd5b5050505050505b50565b33611001146200193957604051630f22c43960e41b81526110016004820152602401620012e3565b60005462010000900460ff16156200196457604051631785c68160e01b815260040160405180910390fd5b6000604583836040516200197a9291906200a1a6565b908152604051908190036020019020546001600160a01b03169050620019a2603f8262008ced565b620019c05760405163056e881160e01b815260040160405180910390fd5b6001600160a01b038116600090815260416020526040812090620019e7610258426200a1cc565b604a546000828152604b60205260409020549192501162001a1b5760405163bd52fcdb60e01b815260040160405180910390fd5b6000818152604b6020526040812080546001929062001a3c9084906200a1ef565b909155505060405160469062001a5690879087906200a1a6565b90815260200160405180910390205460001415801562001aa65750426102586046878760405162001a899291906200a1a6565b90815260200160405180910390205462001aa491906200a1ef565b105b1562001ac557604051631898eb6b60e01b815260040160405180910390fd5b60008062001ad585600262008d10565b915091508162001af857604051631b919bb160e11b815260040160405180910390fd5b6002840154603c5460405163045bc4d160e41b815260048101919091526000916001600160a01b0316906345bc4d10906024016020604051808303816000875af115801562001b4b573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019062001b7191906200a205565b905062001b7f858362008d98565b84546040516335409f7f60e01b81526001600160a01b039091166004820152611000906335409f7f90602401600060405180830381600087803b15801562001bc657600080fd5b505af115801562001bdb573d6000803e3d6000fd5b50505050856001600160a01b03167f6e9a2ee7aee95665e3a774a212eb11441b217e3e4656ab9563793094689aabb28383600260405162001c1f939291906200a21f565b60405180910390a26002850154604051633041949b60e01b815261200591633041949b9162001c5d916001600160a01b0316908a906004016200a18c565b600060405180830381600087803b15801562001c7857600080fd5b505af115801562001c8d573d6000803e3d6000fd5b505050505050505050505050565b6060336120001462001cc557604051630f22c43960e41b81526120006004820152602401620012e3565b60005462010000900460ff161562001cf057604051631785c68160e01b815260040160405180910390fd5b6034805460ff1916600117905560405162461bcd60e51b815260206004820152600a60248201526919195c1c9958d85d195960b21b6044820152606401620012e3565b60005462010000900460ff161562001d5e57604051631785c68160e01b815260040160405180910390fd5b3360009081526001602052604090205460ff161562001d905760405163b1d02c3d60e01b815260040160405180910390fd5b62001d9a62008e8c565b62001da7603f8262008ced565b62001dc55760405163056e881160e01b815260040160405180910390fd5b62001dcf62008ef3565b600082900362001df257604051636490ffd360e01b815260040160405180910390fd5b600062001dfe62008e8c565b6001600160a01b0381166000908152604f602052604090208054604e54929350909162001e2c86836200a1ef565b111562001e4c5760405163091af98560e21b815260040160405180910390fd5b60005b8581101562001f3257600087878381811062001e6f5762001e6f6200a25a565b905060200201350362001e9557604051636490ffd360e01b815260040160405180910390fd5b600062001ea48260016200a1ef565b90505b8681101562001f1c5787878281811062001ec55762001ec56200a25a565b9050602002013588888481811062001ee15762001ee16200a25a565b905060200201350362001f0757604051632205e3c760e11b815260040160405180910390fd5b8062001f13816200a270565b91505062001ea7565b508062001f29816200a270565b91505062001e4f565b5060005b8581101562001fd15760005b8281101562001fbb5783818154811062001f605762001f606200a25a565b906000526020600020015488888481811062001f805762001f806200a25a565b905060200201350362001fa657604051632205e3c760e11b815260040160405180910390fd5b8062001fb2816200a270565b91505062001f42565b508062001fc8816200a270565b91505062001f36565b5060005b8581101562001907578287878381811062001ff45762001ff46200a25a565b835460018101855560009485526020948590209190940292909201359190920155506001600160a01b0384167f7c4ff4c9a343a2daef608f3b5a91016e994a15fc0ef8611109e4f45823249f298888848181106200205657620020566200a25a565b905060200201356040516200206d91815260200190565b60405180910390a28062002081816200a270565b91505062001fd5565b6000816200209a603f8262008ced565b620020b85760405163056e881160e01b815260040160405180910390fd5b6001600160a01b038084166000908152604160205260409020600d01541691505b50919050565b60608082806001600160401b03811115620020fe57620020fe6200992f565b60405190808252806020026020018201604052801562002128578160200160208202803683370190505b509250806001600160401b038111156200214657620021466200992f565b6040519080825280602002602001820160405280156200217b57816020015b6060815260200190600190039081620021655790505b50915060005b81811015620026a4576000868683818110620021a157620021a16200a25a565b9050602002016020810190620021b89190620097c0565b6001600160a01b0380821660009081526041602090815260408083208151610180810183528154861681526001820154861693810193909352600281015490941690820152600383015460608201526004830180549495509193909291608084019162002225906200a156565b80601f016020809104026020016040519081016040528092919081815260200182805462002253906200a156565b8015620022a45780601f106200227857610100808354040283529160200191620022a4565b820191906000526020600020905b8154815290600101906020018083116200228657829003601f168201915b5050505050815260200160058201604051806080016040529081600082018054620022cf906200a156565b80601f0160208091040260200160405190810160405280929190818152602001828054620022fd906200a156565b80156200234e5780601f1062002322576101008083540402835291602001916200234e565b820191906000526020600020905b8154815290600101906020018083116200233057829003601f168201915b5050505050815260200160018201805462002369906200a156565b80601f016020809104026020016040519081016040528092919081815260200182805462002397906200a156565b8015620023e85780601f10620023bc57610100808354040283529160200191620023e8565b820191906000526020600020905b815481529060010190602001808311620023ca57829003601f168201915b5050505050815260200160028201805462002403906200a156565b80601f016020809104026020016040519081016040528092919081815260200182805462002431906200a156565b8015620024825780601f10620024565761010080835404028352916020019162002482565b820191906000526020600020905b8154815290600101906020018083116200246457829003601f168201915b505050505081526020016003820180546200249d906200a156565b80601f0160208091040260200160405190810160405280929190818152602001828054620024cb906200a156565b80156200251c5780601f10620024f0576101008083540402835291602001916200251c565b820191906000526020600020905b815481529060010190602001808311620024fe57829003601f168201915b505050919092525050508152604080516060808201835260098501546001600160401b038082168452600160401b82048116602080860191909152600160801b9092041683850152840191909152600a84015460ff16151582840152600b84015490830152600c8301546080830152600d8301546001600160a01b031660a0830152805161026081019182905260c09092019190600e84019060139082845b815481526020019060010190808311620025bb5750505050508152505090508060000151868481518110620025f457620025f46200a25a565b6001600160a01b039283166020918202929092018101919091529083166000908152604f8252604090819020805482518185028101850190935280835291929091908301828280156200266757602002820191906000526020600020905b81548152602001906001019080831162002652575b50505050508584815181106200268157620026816200a25a565b6020026020010181905250505080806200269b906200a270565b91505062002181565b50505b9250929050565b600054630100000090046001600160a01b03163314620026e1576040516306fbb1e360e01b815260040160405180910390fd5b6001600160a01b0381166000818152600160208190526040808320805460ff1916909217909155517f7fd26be6fc92aff63f1f4409b2b2ddeb272a888031d7f55ec830485ec61941869190a250565b60005462010000900460ff16156200275b57604051631785c68160e01b815260040160405180910390fd5b3360009081526001602052604090205460ff16156200278d5760405163b1d02c3d60e01b815260040160405180910390fd5b806200279b603f8262008ced565b620027b95760405163056e881160e01b815260040160405180910390fd5b6001600160a01b0382166000908152604160205260409020600a81015460ff16620027f757604051634b6b857d60e01b815260040160405180910390fd5b6036546002820154604051630913db4760e01b81526001600160a01b03868116600483015290911690630913db4790602401602060405180830381865afa15801562002847573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906200286d91906200a205565b10156200288d576040516317b204bf60e11b815260040160405180910390fd5b4281600b01541115620028b35760405163170cb76760e21b815260040160405180910390fd5b600a8101805460ff191690556049805460019190600090620028d79084906200a28c565b90915550506040516001600160a01b038416907f9390b453426557da5ebdc31f19a37753ca04addf656d32f35232211bb2af3f1990600090a2505050565b60005462010000900460ff16156200294057604051631785c68160e01b815260040160405180910390fd5b3360009081526001602052604090205460ff1615620029725760405163b1d02c3d60e01b815260040160405180910390fd5b6200297c62008f06565b62002989603f8262008ced565b620029a75760405163056e881160e01b815260040160405180910390fd5b6001600160a01b038216620029cf57604051636520611b60e11b815260040160405180910390fd5b6001600160a01b03828116600090815260436020526040902054161562002a0957604051631e6f587560e11b815260040160405180910390fd5b600062002a1562008f06565b6001600160a01b0381166000908152604160205260409020600c81015491925090429062002a4790610258906200a1ef565b111562002a6757604051631f92cdbd60e11b815260040160405180910390fd5b80546001600160a01b039081166000908152604460209081526040808320429081905585548986166001600160a01b031991821681178855600c88019290925581855260439093528184208054958816959093168517909255519092917f6e4e747ca35203f16401c69805c7dd52fff67ef60b0ebc5c7fe16890530f223591a350505050565b3362002afb603f8262008ced565b62002b195760405163056e881160e01b815260040160405180910390fd5b60005462010000900460ff161562002b4457604051631785c68160e01b815260040160405180910390fd5b3360009081526001602052604090205460ff161562002b765760405163b1d02c3d60e01b815260040160405180910390fd5b6001600160a01b038281166000908152604d6020526040902054161562002bb05760405163bebdc75760e01b815260040160405180910390fd5b62002bbd603f8362008ced565b1562002bdc5760405163bebdc75760e01b815260040160405180910390fd5b336000818152604160205260409020600d01546001600160a01b03908116908416810362002c1d5760405163bebdc75760e01b815260040160405180910390fd5b6001600160a01b0381161562002c54576001600160a01b0381166000908152604d6020526040902080546001600160a01b03191690555b6001600160a01b038281166000908152604160205260409020600d0180546001600160a01b03191691861691821790551562002cb9576001600160a01b038481166000908152604d6020526040902080546001600160a01b0319169184169190911790555b836001600160a01b0316816001600160a01b0316836001600160a01b03167fcbb728765de145e99c00e8ae32a325231e850359b7b8a6da3b84d672ab3f1d0a60405160405180910390a450505050565b600054630100000090046001600160a01b0316331462002d3c576040516306fbb1e360e01b815260040160405180910390fd5b6001600160a01b038116600081815260016020526040808220805460ff19169055517fe0db3499b7fdc3da4cddff5f45d694549c19835e7f719fb5606d3ad1a5de40119190a250565b60005462010000900460ff161562002db057604051631785c68160e01b815260040160405180910390fd5b3360009081526001602052604090205460ff161562002de25760405163b1d02c3d60e01b815260040160405180910390fd5b8162002df0603f8262008ced565b62002e0e5760405163056e881160e01b815260040160405180910390fd5b8160000362002e3057604051639811e0c760e01b815260040160405180910390fd5b6001600160a01b038084166000908152604160209081526040808320815161018081018352815486168152600182015486169381019390935260028101549094169082015260038301546060820152600483018054339491608084019162002e98906200a156565b80601f016020809104026020016040519081016040528092919081815260200182805462002ec6906200a156565b801562002f175780601f1062002eeb5761010080835404028352916020019162002f17565b820191906000526020600020905b81548152906001019060200180831162002ef957829003601f168201915b505050505081526020016005820160405180608001604052908160008201805462002f42906200a156565b80601f016020809104026020016040519081016040528092919081815260200182805462002f70906200a156565b801562002fc15780601f1062002f955761010080835404028352916020019162002fc1565b820191906000526020600020905b81548152906001019060200180831162002fa357829003601f168201915b5050505050815260200160018201805462002fdc906200a156565b80601f01602080910402602001604051908101604052809291908181526020018280546200300a906200a156565b80156200305b5780601f106200302f576101008083540402835291602001916200305b565b820191906000526020600020905b8154815290600101906020018083116200303d57829003601f168201915b5050505050815260200160028201805462003076906200a156565b80601f0160208091040260200160405190810160405280929190818152602001828054620030a4906200a156565b8015620030f55780601f10620030c957610100808354040283529160200191620030f5565b820191906000526020600020905b815481529060010190602001808311620030d757829003601f168201915b5050505050815260200160038201805462003110906200a156565b80601f01602080910402602001604051908101604052809291908181526020018280546200313e906200a156565b80156200318f5780601f1062003163576101008083540402835291602001916200318f565b820191906000526020600020905b8154815290600101906020018083116200317157829003601f168201915b505050919092525050508152604080516060808201835260098501546001600160401b038082168452600160401b82048116602080860191909152600160801b9092041683850152840191909152600a84015460ff16151582840152600b84015490830152600c8301546080830152600d8301546001600160a01b031660a0830152805161026081019182905260c09092019190600e84019060139082845b8154815260200190600101908083116200322e575050509190925250505060408082015190516326ccee8b60e11b81526001600160a01b0385811660048301526024820188905292935060009290911690634d99dd16906044016020604051808303816000875af1158015620032a8573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190620032ce91906200a205565b9050826001600160a01b0316866001600160a01b03167f3aace7340547de7b9156593a7652dc07ee900cea3fd8f82cb6c9d38b4082980287846040516200331f929190918252602082015260400190565b60405180910390a3856001600160a01b0316836001600160a01b0316036200334c576200334c8662008f47565b6040808301519051633041949b60e01b815261200591633041949b9162003379919087906004016200a18c565b600060405180830381600087803b1580156200339457600080fd5b505af1158015620033a9573d6000803e3d6000fd5b50505050505050505050565b60005462010000900460ff1615620033e057604051631785c68160e01b815260040160405180910390fd5b3360009081526001602052604090205460ff1615620034125760405163b1d02c3d60e01b815260040160405180910390fd5b8362003420603f8262008ced565b6200343e5760405163056e881160e01b815260040160405180910390fd5b836200344c603f8262008ced565b6200346a5760405163056e881160e01b815260040160405180910390fd5b6034805460ff1916600117905560008490036200349a57604051639811e0c760e01b815260040160405180910390fd5b846001600160a01b0316866001600160a01b031603620034cd5760405163f0e3e62960e01b815260040160405180910390fd5b6001600160a01b038087166000908152604160209081526040808320815161018081018352815486168152600182015486169381019390935260028101549094169082015260038301546060820152600483018054339491608084019162003535906200a156565b80601f016020809104026020016040519081016040528092919081815260200182805462003563906200a156565b8015620035b45780601f106200358857610100808354040283529160200191620035b4565b820191906000526020600020905b8154815290600101906020018083116200359657829003601f168201915b5050505050815260200160058201604051806080016040529081600082018054620035df906200a156565b80601f01602080910402602001604051908101604052809291908181526020018280546200360d906200a156565b80156200365e5780601f1062003632576101008083540402835291602001916200365e565b820191906000526020600020905b8154815290600101906020018083116200364057829003601f168201915b5050505050815260200160018201805462003679906200a156565b80601f0160208091040260200160405190810160405280929190818152602001828054620036a7906200a156565b8015620036f85780601f10620036cc57610100808354040283529160200191620036f8565b820191906000526020600020905b815481529060010190602001808311620036da57829003601f168201915b5050505050815260200160028201805462003713906200a156565b80601f016020809104026020016040519081016040528092919081815260200182805462003741906200a156565b8015620037925780601f10620037665761010080835404028352916020019162003792565b820191906000526020600020905b8154815290600101906020018083116200377457829003601f168201915b50505050508152602001600382018054620037ad906200a156565b80601f0160208091040260200160405190810160405280929190818152602001828054620037db906200a156565b80156200382c5780601f1062003800576101008083540402835291602001916200382c565b820191906000526020600020905b8154815290600101906020018083116200380e57829003601f168201915b505050919092525050508152604080516060808201835260098501546001600160401b038082168452600160401b82048116602080860191909152600160801b9092041683850152840191909152600a84015460ff16151582840152600b84015490830152600c8301546080830152600d8301546001600160a01b031660a0830152805161026081019182905260c09092019190600e84019060139082845b815481526020019060010190808311620038cb57505050919092525050506001600160a01b0380891660009081526041602090815260408083208151610180810183528154861681526001820154861693810193909352600281015490941690820152600383015460608201526004830180549495509193909291608084019162003956906200a156565b80601f016020809104026020016040519081016040528092919081815260200182805462003984906200a156565b8015620039d55780601f10620039a957610100808354040283529160200191620039d5565b820191906000526020600020905b815481529060010190602001808311620039b757829003601f168201915b505050505081526020016005820160405180608001604052908160008201805462003a00906200a156565b80601f016020809104026020016040519081016040528092919081815260200182805462003a2e906200a156565b801562003a7f5780601f1062003a535761010080835404028352916020019162003a7f565b820191906000526020600020905b81548152906001019060200180831162003a6157829003601f168201915b5050505050815260200160018201805462003a9a906200a156565b80601f016020809104026020016040519081016040528092919081815260200182805462003ac8906200a156565b801562003b195780601f1062003aed5761010080835404028352916020019162003b19565b820191906000526020600020905b81548152906001019060200180831162003afb57829003601f168201915b5050505050815260200160028201805462003b34906200a156565b80601f016020809104026020016040519081016040528092919081815260200182805462003b62906200a156565b801562003bb35780601f1062003b875761010080835404028352916020019162003bb3565b820191906000526020600020905b81548152906001019060200180831162003b9557829003601f168201915b5050505050815260200160038201805462003bce906200a156565b80601f016020809104026020016040519081016040528092919081815260200182805462003bfc906200a156565b801562003c4d5780601f1062003c215761010080835404028352916020019162003c4d565b820191906000526020600020905b81548152906001019060200180831162003c2f57829003601f168201915b505050919092525050508152604080516060808201835260098501546001600160401b038082168452600160401b82048116602080860191909152600160801b9092041683850152840191909152600a84015460ff16151582840152600b84015490830152600c8301546080830152600d8301546001600160a01b031660a0830152805161026081019182905260c09092019190600e84019060139082845b81548152602001906001019080831162003cec5750505050508152505090508060e00151801562003d2f5750876001600160a01b0316836001600160a01b031614155b1562003d4e57604051636468920360e01b815260040160405180910390fd5b60408083015190516352e82ce560e11b81526001600160a01b038581166004830152602482018a9052600092169063a5d059ca906044016020604051808303816000875af115801562003da5573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019062003dcb91906200a205565b905060375481101562003df15760405163dc6f0bdd60e01b815260040160405180910390fd5b896001600160a01b0316846001600160a01b031614801562003e8657506036546040808501519051630913db4760e01b81526001600160a01b038d8116600483015290911690630913db4790602401602060405180830381865afa15801562003e5e573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019062003e8491906200a205565b105b1562003ea5576040516317b204bf60e11b815260040160405180910390fd5b6000620186a0603a548362003ebb91906200a2a2565b62003ec791906200a1cc565b9050600083604001516001600160a01b03168260405160006040518083038185875af1925050503d806000811462003f1c576040519150601f19603f3d011682016040523d82523d6000602084013e62003f21565b606091505b505090508062003f44576040516312171d8360e31b815260040160405180910390fd5b62003f5082846200a28c565b60408086015190516317066a5760e21b81526001600160a01b03898116600483015292955060009290911690635c19a95c90869060240160206040518083038185885af115801562003fa6573d6000803e3d6000fd5b50505050506040513d601f19601f8201168201806040525081019062003fcd91906200a205565b9050866001600160a01b03168c6001600160a01b03168e6001600160a01b03167ffdac6e81913996d95abcc289e90f2d8bd235487ce6fe6f821e7d21002a1915b48e858960405162004032939291909283526020830191909152604082015260600190565b60405180910390a46040805160028082526060820183526000926020830190803683370190505090508660400151816000815181106200407657620040766200a25a565b60200260200101906001600160a01b031690816001600160a01b031681525050856040015181600181518110620040b157620040b16200a25a565b6001600160a01b0390921660209283029190910190910152604051634484077560e01b815261200590634484077590620040f29084908c906004016200a2bc565b600060405180830381600087803b1580156200410d57600080fd5b505af115801562004122573d6000803e3d6000fd5b505050508a1562004194576120056001600160a01b031663e5ed5b1e898f6040518363ffffffff1660e01b81526004016200415f9291906200a18c565b600060405180830381600087803b1580156200417a57600080fd5b505af11580156200418f573d6000803e3d6000fd5b505050505b50506034805460ff19169055505050505050505050505050565b60005462010000900460ff1615620041d957604051631785c68160e01b815260040160405180910390fd5b3360009081526001602052604090205460ff16156200420b5760405163b1d02c3d60e01b815260040160405180910390fd5b6200421562008f06565b62004222603f8262008ced565b620042405760405163056e881160e01b815260040160405180910390fd5b60006200424c62008f06565b6001600160a01b0381166000908152604160205260409020600c8101549192509042906200427e90610258906200a1ef565b11156200429e57604051631f92cdbd60e11b815260040160405180910390fd5b60098101546001600160401b03600160401b90910481169085161115620042d85760405163dc81db8560e01b815260040160405180910390fd5b60098101546000906001600160401b03908116908616101562004316576009820154620043109086906001600160401b03166200a2e8565b62004330565b600982015462004330906001600160401b0316866200a2e8565b60098301546001600160401b039182169250600160801b9004168111156200436b5760405163dc81db8560e01b815260040160405180910390fd5b60098201805467ffffffffffffffff19166001600160401b03871690811790915542600c8401556040519081526001600160a01b038416907f78cdd96edf59e09cfd4d26ef6ef6c92d166effe6a40970c54821206d541932cb9060200160405180910390a25050505050565b60608060606000620043ea603f62009065565b90508086101562004a7357841562004403578462004405565b805b94506000856200441688846200a28c565b116200442e576200442887836200a28c565b62004430565b855b9050806001600160401b038111156200444d576200444d6200992f565b60405190808252806020026020018201604052801562004477578160200160208202803683370190505b509450806001600160401b038111156200449557620044956200992f565b604051908082528060200260200182016040528015620044bf578160200160208202803683370190505b509350806001600160401b03811115620044dd57620044dd6200992f565b6040519080825280602002602001820160405280156200451257816020015b6060815260200190600190039081620044fc5790505b50925060005b8181101562004a705760006200453c62004533838b6200a1ef565b603f9062009070565b6001600160a01b03808216600090815260416020908152604080832081516101808101835281548616815260018201548616938101939093526002810154909416908201526003830154606082015260048301805494955091939092916080840191620045a9906200a156565b80601f0160208091040260200160405190810160405280929190818152602001828054620045d7906200a156565b8015620046285780601f10620045fc5761010080835404028352916020019162004628565b820191906000526020600020905b8154815290600101906020018083116200460a57829003601f168201915b505050505081526020016005820160405180608001604052908160008201805462004653906200a156565b80601f016020809104026020016040519081016040528092919081815260200182805462004681906200a156565b8015620046d25780601f10620046a657610100808354040283529160200191620046d2565b820191906000526020600020905b815481529060010190602001808311620046b457829003601f168201915b50505050508152602001600182018054620046ed906200a156565b80601f01602080910402602001604051908101604052809291908181526020018280546200471b906200a156565b80156200476c5780601f1062004740576101008083540402835291602001916200476c565b820191906000526020600020905b8154815290600101906020018083116200474e57829003601f168201915b5050505050815260200160028201805462004787906200a156565b80601f0160208091040260200160405190810160405280929190818152602001828054620047b5906200a156565b8015620048065780601f10620047da5761010080835404028352916020019162004806565b820191906000526020600020905b815481529060010190602001808311620047e857829003601f168201915b5050505050815260200160038201805462004821906200a156565b80601f01602080910402602001604051908101604052809291908181526020018280546200484f906200a156565b8015620048a05780601f106200487457610100808354040283529160200191620048a0565b820191906000526020600020905b8154815290600101906020018083116200488257829003601f168201915b505050919092525050508152604080516060808201835260098501546001600160401b038082168452600160401b82048116602080860191909152600160801b9092041683850152840191909152600a84015460ff16151582840152600b84015490830152600c8301546080830152600d8301546001600160a01b031660a0830152805161026081019182905260c09092019190600e84019060139082845b8154815260200190600101908083116200493f57505050505081525050905080600001518884815181106200497857620049786200a25a565b60200260200101906001600160a01b031690816001600160a01b0316815250508060e0015162004a115780604001516001600160a01b03166315d1f8986040518163ffffffff1660e01b8152600401602060405180830381865afa158015620049e5573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019062004a0b91906200a205565b62004a14565b60005b87848151811062004a295762004a296200a25a565b602002602001018181525050806080015186848151811062004a4f5762004a4f6200a25a565b602002602001018190525050508062004a68906200a270565b905062004518565b50505b92959194509250565b60005462010000900460ff161562004aa757604051631785c68160e01b815260040160405180910390fd5b3360009081526001602052604090205460ff161562004ad95760405163b1d02c3d60e01b815260040160405180910390fd5b3362004ae7603f8262008ced565b1562004b0657604051635f28f62b60e01b815260040160405180910390fd5b6001600160a01b038181166000908152604d6020526040902054161562004b4057604051631a0a9b9f60e21b815260040160405180910390fd5b6001600160a01b03888116600090815260436020526040902054161562004b7a57604051631e6f587560e11b815260040160405180910390fd5b60006001600160a01b03166045888860405162004b999291906200a1a6565b908152604051908190036020019020546001600160a01b03161462004bd1576040516311fdb94760e01b815260040160405180910390fd5b600062004bdf83806200a312565b60405160200162004bf29291906200a1a6565b60408051601f1981840301815291815281516020928301206000818152604290935291205490915060ff161562004c3c5760405163c0bf414360e01b815260040160405180910390fd5b600062004c52670de0b6b3a7640000346200a28c565b905060365481101562004c78576040516317b204bf60e11b815260040160405180910390fd5b6001600160a01b038a1662004ca057604051636520611b60e11b815260040160405180910390fd5b61138862004cb5604087016020880162009c4e565b6001600160401b0316118062004cfb575062004cd8604086016020870162009c4e565b6001600160401b031662004cf0602087018762009c4e565b6001600160401b0316115b8062004d3a575062004d14604086016020870162009c4e565b6001600160401b031662004d2f606087016040880162009c4e565b6001600160401b0316115b1562004d595760405163dc81db8560e01b815260040160405180910390fd5b62004da462004d6985806200a312565b8080601f0160208091040260200160405190810160405280939291908181526020018383808284376000920191909152506200907e92505050565b62004dc257604051635dba5ad760e01b815260040160405180910390fd5b62004dd1838a8a8a8a62009220565b62004def57604051631647e3cb60e11b815260040160405180910390fd5b600062004e3d8462004e0287806200a312565b8080601f0160208091040260200160405190810160405280939291908181526020018383808284376000920191909152506200935092505050565b905062004e4c603f8562009451565b506000838152604260209081526040808320805460ff191660019081179091556001600160a01b0380891680865260419094529190932080548f83166001600160a01b03199182161782559381018054851690931790925560028201805491851691909316179091554260038201556004810162004ecc8b8d836200a3ba565b50856005820162004ede82826200a482565b508790506009820162004ef282826200a5bb565b505042600c8201556001600160a01b038c81166000908152604360205260409081902080546001600160a01b0319169288169290921790915551859060459062004f40908e908e906200a1a6565b908152602001604051809103902060006101000a8154816001600160a01b0302191690836001600160a01b03160217905550816001600160a01b0316856001600160a01b03168d6001600160a01b03167faecd9fb95e79c75a3a1de93362c6be5fe6ab65770d8614be583884161cd8228d8e8e60405162004fc39291906200a68b565b60405180910390a460408051848152602081018590526001600160a01b0387169182917f24d7bda8602b916d64417f0dbfe2e2e88ec9b1157bd9f596dfdb91ba26624e04910160405180910390a360408051670de0b6b3a7640000808252602082015261dead916001600160a01b038816917f24d7bda8602b916d64417f0dbfe2e2e88ec9b1157bd9f596dfdb91ba26624e04910160405180910390a3604051633041949b60e01b815261200590633041949b906200508990859089906004016200a18c565b600060405180830381600087803b158015620050a457600080fd5b505af1158015620050b9573d6000803e3d6000fd5b50505050505050505050505050505050565b604080516060810182526000808252602082018190529181019190915281620050f6603f8262008ced565b620051145760405163056e881160e01b815260040160405180910390fd5b50506001600160a01b031660009081526041602090815260409182902082516060810184526009909101546001600160401b038082168352600160401b8204811693830193909352600160801b90049091169181019190915290565b6001600160a01b03808216600090815260416020908152604080832081516101808101835281548616815260018201548616938101939093526002810154909416908201526003830154606082810191909152600484018054919491608084019190620051dd906200a156565b80601f01602080910402602001604051908101604052809291908181526020018280546200520b906200a156565b80156200525c5780601f1062005230576101008083540402835291602001916200525c565b820191906000526020600020905b8154815290600101906020018083116200523e57829003601f168201915b505050505081526020016005820160405180608001604052908160008201805462005287906200a156565b80601f0160208091040260200160405190810160405280929190818152602001828054620052b5906200a156565b8015620053065780601f10620052da5761010080835404028352916020019162005306565b820191906000526020600020905b815481529060010190602001808311620052e857829003601f168201915b5050505050815260200160018201805462005321906200a156565b80601f01602080910402602001604051908101604052809291908181526020018280546200534f906200a156565b8015620053a05780601f106200537457610100808354040283529160200191620053a0565b820191906000526020600020905b8154815290600101906020018083116200538257829003601f168201915b50505050508152602001600282018054620053bb906200a156565b80601f0160208091040260200160405190810160405280929190818152602001828054620053e9906200a156565b80156200543a5780601f106200540e576101008083540402835291602001916200543a565b820191906000526020600020905b8154815290600101906020018083116200541c57829003601f168201915b5050505050815260200160038201805462005455906200a156565b80601f016020809104026020016040519081016040528092919081815260200182805462005483906200a156565b8015620054d45780601f10620054a857610100808354040283529160200191620054d4565b820191906000526020600020905b815481529060010190602001808311620054b657829003601f168201915b505050919092525050508152604080516060808201835260098501546001600160401b038082168452600160401b82048116602080860191909152600160801b9092041683850152840191909152600a84015460ff16151582840152600b84015490830152600c8301546080830152600d8301546001600160a01b031660a0830152805161026081019182905260c09092019190600e84019060139082845b815481526020019060010190808311620055735750505091909252505050608001519392505050565b3361100114620055c457604051630f22c43960e41b81526110016004820152602401620012e3565b6001600160a01b0380821660009081526043602052604090205416620055ec603f8262008ced565b6200560a5760405163056e881160e01b815260040160405180910390fd5b6001600160a01b038181166000908152604160205260408082206002810154603b54925163045bc4d160e41b81526004810193909352909316906345bc4d10906024016020604051808303816000875af11580156200566d573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906200569391906200a205565b90506000603d5442620056a791906200a1ef565b9050620056b5838262008d98565b836001600160a01b03167f6e9a2ee7aee95665e3a774a212eb11441b217e3e4656ab9563793094689aabb282846001604051620056f5939291906200a21f565b60405180910390a26002830154604051633041949b60e01b815261200591633041949b9162005733916001600160a01b03169088906004016200a18c565b600060405180830381600087803b1580156200574e57600080fd5b505af115801562005763573d6000803e3d6000fd5b505050505050505050565b600054610100900460ff16158080156200578f5750600054600160ff909116105b80620057ab5750303b158015620057ab575060005460ff166001145b620058105760405162461bcd60e51b815260206004820152602e60248201527f496e697469616c697a61626c653a20636f6e747261637420697320616c72656160448201526d191e481a5b9a5d1a585b1a5e995960921b6064820152608401620012e3565b6000805460ff19166001179055801562005834576000805461ff0019166101001790555b334114620058555760405163022d8c9560e31b815260040160405180910390fd5b3a1562005875576040516383f1b1d360e01b815260040160405180910390fd5b611388603555686c6b935b8bbd400000603655670de0b6b3a7640000603755602d603855607860398190556002603a819055678ac7230489e80000603b55680ad78ebc5ac6200000603c55603d9190915560b4603e55604a55620058ed7304d63abcd2b9b1baa327f2dda0f873f197ccd18662009468565b80156200190e576000805461ff0019169055604051600181527f7f26b83ff96e1f2b6a682f133852f6798a09c465da95921460cefb38474024989060200160405180910390a150565b33612000146200595e57604051630f22c43960e41b81526120006004820152602401620012e3565b60405162461bcd60e51b815260206004820152600a60248201526919195c1c9958d85d195960b21b6044820152606401620012e3565b600054630100000090046001600160a01b03163314620059c7576040516306fbb1e360e01b815260040160405180910390fd5b60005462010000900460ff1615620059f257604051631785c68160e01b815260040160405180910390fd5b6000805462ff00001916620100001781556040517f9e87fac88ff661f02d44f95383c817fece4bce600a3dab7a54406878b965e7529190a1565b600062005a3b603f8462008ced565b62005a595760405163056e881160e01b815260040160405180910390fd5b6001600160a01b0383811660009081526041602052604090819020600201549051636bbf224960e01b815260048101859052911690636bbf2249906024015b602060405180830381865afa15801562005ab6573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019062005adc91906200a205565b90505b92915050565b60005462010000900460ff161562005b1057604051631785c68160e01b815260040160405180910390fd5b3360009081526001602052604090205460ff161562005b425760405163b1d02c3d60e01b815260040160405180910390fd5b8162005b50603f8262008ced565b62005b6e5760405163056e881160e01b815260040160405180910390fd5b603754349081101562005b945760405163dc6f0bdd60e01b815260040160405180910390fd5b6001600160a01b038085166000908152604160209081526040808320815161018081018352815486168152600182015486169381019390935260028101549094169082015260038301546060820152600483018054339491608084019162005bfc906200a156565b80601f016020809104026020016040519081016040528092919081815260200182805462005c2a906200a156565b801562005c7b5780601f1062005c4f5761010080835404028352916020019162005c7b565b820191906000526020600020905b81548152906001019060200180831162005c5d57829003601f168201915b505050505081526020016005820160405180608001604052908160008201805462005ca6906200a156565b80601f016020809104026020016040519081016040528092919081815260200182805462005cd4906200a156565b801562005d255780601f1062005cf95761010080835404028352916020019162005d25565b820191906000526020600020905b81548152906001019060200180831162005d0757829003601f168201915b5050505050815260200160018201805462005d40906200a156565b80601f016020809104026020016040519081016040528092919081815260200182805462005d6e906200a156565b801562005dbf5780601f1062005d935761010080835404028352916020019162005dbf565b820191906000526020600020905b81548152906001019060200180831162005da157829003601f168201915b5050505050815260200160028201805462005dda906200a156565b80601f016020809104026020016040519081016040528092919081815260200182805462005e08906200a156565b801562005e595780601f1062005e2d5761010080835404028352916020019162005e59565b820191906000526020600020905b81548152906001019060200180831162005e3b57829003601f168201915b5050505050815260200160038201805462005e74906200a156565b80601f016020809104026020016040519081016040528092919081815260200182805462005ea2906200a156565b801562005ef35780601f1062005ec75761010080835404028352916020019162005ef3565b820191906000526020600020905b81548152906001019060200180831162005ed557829003601f168201915b505050919092525050508152604080516060808201835260098501546001600160401b038082168452600160401b82048116602080860191909152600160801b9092041683850152840191909152600a84015460ff16151582840152600b84015490830152600c8301546080830152600d8301546001600160a01b031660a0830152805161026081019182905260c09092019190600e84019060139082845b81548152602001906001019080831162005f925750505050508152505090508060e00151801562005fd55750856001600160a01b0316826001600160a01b031614155b1562005ff457604051636468920360e01b815260040160405180910390fd5b60408082015190516317066a5760e21b81526001600160a01b0384811660048301526000921690635c19a95c90869060240160206040518083038185885af115801562006045573d6000803e3d6000fd5b50505050506040513d601f19601f820116820180604052508101906200606c91906200a205565b9050826001600160a01b0316876001600160a01b03167f24d7bda8602b916d64417f0dbfe2e2e88ec9b1157bd9f596dfdb91ba26624e048387604051620060bd929190918252602082015260400190565b60405180910390a36040808301519051633041949b60e01b815261200591633041949b91620060f2919087906004016200a18c565b600060405180830381600087803b1580156200610d57600080fd5b505af115801562006122573d6000803e3d6000fd5b50505050851562001907576040516372f6ad8f60e11b81526120059063e5ed5b1e90620061569086908b906004016200a18c565b600060405180830381600087803b1580156200617157600080fd5b505af115801562006186573d6000803e3d6000fd5b5050505050505050505050565b60005462010000900460ff1615620061be57604051631785c68160e01b815260040160405180910390fd5b3360009081526001602052604090205460ff1615620061f05760405163b1d02c3d60e01b815260040160405180910390fd5b620061fa62008e8c565b62006207603f8262008ced565b620062255760405163056e881160e01b815260040160405180910390fd5b60006200623162008e8c565b6001600160a01b0381166000908152604f6020526040812080549293509190859003620063085760005b81811015620062dc57836001600160a01b03167f08e60c1b84aab23d99a7262015e647d5ffd6c6e08f78205e1df6774c48e1427a848381548110620062a457620062a46200a25a565b9060005260206000200154604051620062bf91815260200190565b60405180910390a280620062d3816200a270565b9150506200625b565b506001600160a01b0383166000908152604f6020526040812062006300916200975a565b505050505050565b60005b85811015620064665760008787838181106200632b576200632b6200a25a565b90506020020135905060005b838110156200644e57818582815481106200635657620063566200a25a565b906000526020600020015403620064395784620063756001866200a28c565b815481106200638857620063886200a25a565b9060005260206000200154858281548110620063a857620063a86200a25a565b906000526020600020018190555084805480620063c957620063c96200a6a1565b600190038181906000526020600020016000905590558380620063ec906200a6b7565b945050856001600160a01b03167f08e60c1b84aab23d99a7262015e647d5ffd6c6e08f78205e1df6774c48e1427a836040516200642b91815260200190565b60405180910390a26200644e565b8062006445816200a270565b91505062006337565b505080806200645d906200a270565b9150506200630b565b50815460000362006300576001600160a01b0383166000908152604f6020526040812062006300916200975a565b505050565b620064c56040518060800160405280606081526020016060815260200160608152602001606081525090565b81620064d3603f8262008ced565b620064f15760405163056e881160e01b815260040160405180910390fd5b6001600160a01b0383166000908152604160205260409081902081516080810190925260050180548290829062006528906200a156565b80601f016020809104026020016040519081016040528092919081815260200182805462006556906200a156565b8015620065a75780601f106200657b57610100808354040283529160200191620065a7565b820191906000526020600020905b8154815290600101906020018083116200658957829003601f168201915b50505050508152602001600182018054620065c2906200a156565b80601f0160208091040260200160405190810160405280929190818152602001828054620065f0906200a156565b8015620066415780601f10620066155761010080835404028352916020019162006641565b820191906000526020600020905b8154815290600101906020018083116200662357829003601f168201915b505050505081526020016002820180546200665c906200a156565b80601f01602080910402602001604051908101604052809291908181526020018280546200668a906200a156565b8015620066db5780601f10620066af57610100808354040283529160200191620066db565b820191906000526020600020905b815481529060010190602001808311620066bd57829003601f168201915b50505050508152602001600382018054620066f6906200a156565b80601f016020809104026020016040519081016040528092919081815260200182805462006724906200a156565b8015620067755780601f10620067495761010080835404028352916020019162006775565b820191906000526020600020905b8154815290600101906020018083116200675757829003601f168201915b505050505081525050915050919050565b60005462010000900460ff1615620067b157604051631785c68160e01b815260040160405180910390fd5b3360009081526001602052604090205460ff1615620067e35760405163b1d02c3d60e01b815260040160405180910390fd5b620067ef828262009501565b5050565b33611007146200681b57604051630f22c43960e41b81526110076004820152602401620012e3565b620068886040518060400160405280601081526020016f1d1c985b9cd9995c91d85cd31a5b5a5d60821b81525085858080601f01602080910402602001604051908101604052809392919081815260200183838082843760009201919091525092939250506200960d9050565b15620069435760208114620068ba5783838383604051630a5a604160e01b8152600401620012e394939291906200a6d1565b604080516020601f8401819004810282018101909252828152600091620068fd9185858083850183828082843760009201919091525092939250506200966a9050565b90506108fc81108062006911575061271081115b156200693a5784848484604051630a5a604160e01b8152600401620012e394939291906200a6d1565b60355562007760565b620069b46040518060400160405280601481526020017336b4b729b2b6332232b632b3b0ba34b7b721272160611b81525085858080601f01602080910402602001604051908101604052809392919081815260200183838082843760009201919091525092939250506200960d9050565b1562006a7e5760208114620069e65783838383604051630a5a604160e01b8152600401620012e394939291906200a6d1565b604080516020601f840181900481028201810190925282815260009162006a299185858083850183828082843760009201919091525092939250506200966a9050565b9050683635c9adc5dea0000081108062006a4c575069152d02c7e14af680000081115b1562006a755784848484604051630a5a604160e01b8152600401620012e394939291906200a6d1565b60365562007760565b62006af1604051806040016040528060168152602001756d696e44656c65676174696f6e424e424368616e676560501b81525085858080601f01602080910402602001604051908101604052809392919081815260200183838082843760009201919091525092939250506200960d9050565b1562006bb8576020811462006b235783838383604051630a5a604160e01b8152600401620012e394939291906200a6d1565b604080516020601f840181900481028201810190925282815260009162006b669185858083850183828082843760009201919091525092939250506200966a9050565b905067016345785d8a000081108062006b865750678ac7230489e8000081115b1562006baf5784848484604051630a5a604160e01b8152600401620012e394939291906200a6d1565b60375562007760565b62006c29604051806040016040528060148152602001736d6178456c656374656456616c696461746f727360601b81525085858080601f01602080910402602001604051908101604052809392919081815260200183838082843760009201919091525092939250506200960d9050565b1562006ce1576020811462006c5b5783838383604051630a5a604160e01b8152600401620012e394939291906200a6d1565b604080516020601f840181900481028201810190925282815260009162006c9e9185858083850183828082843760009201919091525092939250506200966a9050565b905080158062006caf57506101f481115b1562006cd85784848484604051630a5a604160e01b8152600401620012e394939291906200a6d1565b60385562007760565b62006d4a6040518060400160405280600c81526020016b1d5b989bdb9914195c9a5bd960a21b81525085858080601f01602080910402602001604051908101604052809392919081815260200183838082843760009201919091525092939250506200960d9050565b1562006e07576020811462006d7c5783838383604051630a5a604160e01b8152600401620012e394939291906200a6d1565b604080516020601f840181900481028201810190925282815260009162006dbf9185858083850183828082843760009201919091525092939250506200966a9050565b90506203f48081108062006dd5575062278d0081115b1562006dfe5784848484604051630a5a604160e01b8152600401620012e394939291906200a6d1565b60395562007760565b62006e7560405180604001604052806011815260200170726564656c65676174654665655261746560781b81525085858080601f01602080910402602001604051908101604052809392919081815260200183838082843760009201919091525092939250506200960d9050565b1562006f22576020811462006ea75783838383604051630a5a604160e01b8152600401620012e394939291906200a6d1565b604080516020601f840181900481028201810190925282815260009162006eea9185858083850183828082843760009201919091525092939250506200966a9050565b9050606481111562006f195784848484604051630a5a604160e01b8152600401620012e394939291906200a6d1565b603a5562007760565b62006f9260405180604001604052806013815260200172191bdddb9d1a5b5954db185cda105b5bdd5b9d606a1b81525085858080601f01602080910402602001604051908101604052809392919081815260200183838082843760009201919091525092939250506200960d9050565b1562007054576020811462006fc45783838383604051630a5a604160e01b8152600401620012e394939291906200a6d1565b604080516020601f8401819004810282018101909252828152600091620070079185858083850183828082843760009201919091525092939250506200966a9050565b9050670de0b6b3a7640000811080620070225750603c548110155b156200704b5784848484604051630a5a604160e01b8152600401620012e394939291906200a6d1565b603b5562007760565b620070c26040518060400160405280601181526020017019995b1bdb9e54db185cda105b5bdd5b9d607a1b81525085858080601f01602080910402602001604051908101604052809392919081815260200183838082843760009201919091525092939250506200960d9050565b15620071845760208114620070f45783838383604051630a5a604160e01b8152600401620012e394939291906200a6d1565b604080516020601f8401819004810282018101909252828152600091620071379185858083850183828082843760009201919091525092939250506200966a9050565b9050678ac7230489e80000811080620071525750603b548111155b156200717b5784848484604051630a5a604160e01b8152600401620012e394939291906200a6d1565b603c5562007760565b620071f16040518060400160405280601081526020016f646f776e74696d654a61696c54696d6560801b81525085858080601f01602080910402602001604051908101604052809392919081815260200183838082843760009201919091525092939250506200960d9050565b15620072ae5760208114620072235783838383604051630a5a604160e01b8152600401620012e394939291906200a6d1565b604080516020601f8401819004810282018101909252828152600091620072669185858083850183828082843760009201919091525092939250506200966a9050565b9050620151808110806200727c5750603e548110155b15620072a55784848484604051630a5a604160e01b8152600401620012e394939291906200a6d1565b603d5562007760565b620073196040518060400160405280600e81526020016d66656c6f6e794a61696c54696d6560901b81525085858080601f01602080910402602001604051908101604052809392919081815260200183838082843760009201919091525092939250506200960d9050565b15620073d657602081146200734b5783838383604051630a5a604160e01b8152600401620012e394939291906200a6d1565b604080516020601f84018190048102820181019092528281526000916200738e9185858083850183828082843760009201919091525092939250506200966a9050565b90506203f480811080620073a45750603d548111155b15620073cd5784848484604051630a5a604160e01b8152600401620012e394939291906200a6d1565b603e5562007760565b620074506040518060400160405280601c81526020017f6d617846656c6f6e794265747765656e42726561746865426c6f636b0000000081525085858080601f01602080910402602001604051908101604052809392919081815260200183838082843760009201919091525092939250506200960d9050565b15620074fc5760208114620074825783838383604051630a5a604160e01b8152600401620012e394939291906200a6d1565b604080516020601f8401819004810282018101909252828152600091620074c59185858083850183828082843760009201919091525092939250506200966a9050565b905080600003620074f35784848484604051630a5a604160e01b8152600401620012e394939291906200a6d1565b604a5562007760565b6200756a6040518060400160405280601181526020017039ba30b5b2a43ab1283937ba32b1ba37b960791b81525085858080601f01602080910402602001604051908101604052809392919081815260200183838082843760009201919091525092939250506200960d9050565b156200762a57601481146200759c5783838383604051630a5a604160e01b8152600401620012e394939291906200a6d1565b6000620075e4601484848080601f01602080910402602001604051908101604052809392919081815260200183838082843760009201919091525092939250506200966a9050565b90506001600160a01b038116620076185784848484604051630a5a604160e01b8152600401620012e394939291906200a6d1565b62007623816200966f565b5062007760565b620076916040518060400160405280600a8152602001696d61784e6f646549447360b01b81525085858080601f01602080910402602001604051908101604052809392919081815260200183838082843760009201919091525092939250506200960d9050565b156200773d5760208114620076c35783838383604051630a5a604160e01b8152600401620012e394939291906200a6d1565b604080516020601f8401819004810282018101909252828152600091620077069185858083850183828082843760009201919091525092939250506200966a9050565b905080600003620077345784848484604051630a5a604160e01b8152600401620012e394939291906200a6d1565b604e5562007760565b838383836040516325ee20d560e21b8152600401620012e394939291906200a6d1565b7ff1ce9b2cbf50eeb05769a29e2543fd350cab46894a7dd9978a12d534bb20e633848484846040516200779794939291906200a6d1565b60405180910390a150505050565b60005462010000900460ff1615620077d057604051631785c68160e01b815260040160405180910390fd5b3360009081526001602052604090205460ff1615620078025760405163b1d02c3d60e01b815260040160405180910390fd5b816000816001600160401b038111156200782057620078206200992f565b6040519080825280602002602001820160405280156200784a578160200160208202803683370190505b5090506000805b838110156200794857620078938787838181106200787357620078736200a25a565b90506020020160208101906200788a9190620097c0565b603f9062008ced565b620078b15760405163056e881160e01b815260040160405180910390fd5b60416000888884818110620078ca57620078ca6200a25a565b9050602002016020810190620078e19190620097c0565b6001600160a01b03908116825260208201929092526040016000206002015484519116925082908490839081106200791d576200791d6200a25a565b6001600160a01b039092166020928302919091019091015262007940816200a270565b905062007851565b50604051634484077560e01b8152612005906344840775906200337990859088906004016200a2bc565b606080600062007983603f62009065565b90508085101562007b475783156200799c57836200799e565b805b9350600084620079af87846200a28c565b11620079c757620079c186836200a28c565b620079c9565b845b9050806001600160401b03811115620079e657620079e66200992f565b60405190808252806020026020018201604052801562007a10578160200160208202803683370190505b509350806001600160401b0381111562007a2e5762007a2e6200992f565b60405190808252806020026020018201604052801562007a58578160200160208202803683370190505b50925060005b8181101562007b445762007a776200453382896200a1ef565b85828151811062007a8c5762007a8c6200a25a565b60200260200101906001600160a01b031690816001600160a01b0316815250506041600086838151811062007ac55762007ac56200a25a565b60200260200101516001600160a01b03166001600160a01b0316815260200190815260200160002060020160009054906101000a90046001600160a01b031684828151811062007b195762007b196200a25a565b6001600160a01b039092166020928302919091019091015262007b3c816200a270565b905062007a5e565b50505b9250925092565b60008162007b5e603f8262008ced565b62007b7c5760405163056e881160e01b815260040160405180910390fd5b50506001600160a01b03166000908152604160205260409020600c015490565b336110011462007bc457604051630f22c43960e41b81526110016004820152602401620012e3565b60005462010000900460ff161562007bef57604051631785c68160e01b815260040160405180910390fd5b6001600160a01b038082166000908152604360205260409020541662007c17603f8262008ced565b62007c355760405163056e881160e01b815260040160405180910390fd5b6001600160a01b03811660009081526041602052604081209062007c5c610258426200a1cc565b604a546000828152604b60205260409020549192501162007c905760405163bd52fcdb60e01b815260040160405180910390fd5b6000818152604b6020526040812080546001929062007cb19084906200a1ef565b90915550506001600160a01b0384166000908152604460205260409020541580159062007d0557506001600160a01b038416600090815260446020526040902054429062007d0390610258906200a1ef565b105b1562007d24576040516330abb81d60e21b815260040160405180910390fd5b60008062007d3485600062008d10565b915091508162007d5757604051631b919bb160e11b815260040160405180910390fd5b6002840154603c5460405163045bc4d160e41b815260048101919091526000916001600160a01b0316906345bc4d10906024016020604051808303816000875af115801562007daa573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019062007dd091906200a205565b905062007dde858362008d98565b84546040516335409f7f60e01b81526001600160a01b039091166004820152611000906335409f7f90602401600060405180830381600087803b15801562007e2557600080fd5b505af115801562007e3a573d6000803e3d6000fd5b50505050856001600160a01b03167f6e9a2ee7aee95665e3a774a212eb11441b217e3e4656ab9563793094689aabb28383600060405162007e7e939291906200a21f565b60405180910390a26002850154604051633041949b60e01b815261200591633041949b9162006156916001600160a01b0316908a906004016200a18c565b6001600160a01b038082166000908152604160209081526040808320815161018081018352815486168152600182015486169381019390935260028101549094169082015260038301546060820152600483018054929384938493849390929160808401919062007f2d906200a156565b80601f016020809104026020016040519081016040528092919081815260200182805462007f5b906200a156565b801562007fac5780601f1062007f805761010080835404028352916020019162007fac565b820191906000526020600020905b81548152906001019060200180831162007f8e57829003601f168201915b505050505081526020016005820160405180608001604052908160008201805462007fd7906200a156565b80601f016020809104026020016040519081016040528092919081815260200182805462008005906200a156565b8015620080565780601f106200802a5761010080835404028352916020019162008056565b820191906000526020600020905b8154815290600101906020018083116200803857829003601f168201915b5050505050815260200160018201805462008071906200a156565b80601f01602080910402602001604051908101604052809291908181526020018280546200809f906200a156565b8015620080f05780601f10620080c457610100808354040283529160200191620080f0565b820191906000526020600020905b815481529060010190602001808311620080d257829003601f168201915b505050505081526020016002820180546200810b906200a156565b80601f016020809104026020016040519081016040528092919081815260200182805462008139906200a156565b80156200818a5780601f106200815e576101008083540402835291602001916200818a565b820191906000526020600020905b8154815290600101906020018083116200816c57829003601f168201915b50505050508152602001600382018054620081a5906200a156565b80601f0160208091040260200160405190810160405280929190818152602001828054620081d3906200a156565b8015620082245780601f10620081f85761010080835404028352916020019162008224565b820191906000526020600020905b8154815290600101906020018083116200820657829003601f168201915b505050919092525050508152604080516060808201835260098501546001600160401b038082168452600160401b82048116602080860191909152600160801b9092041683850152840191909152600a84015460ff16151582840152600b84015490830152600c8301546080830152600d8301546001600160a01b031660a0830152805161026081019182905260c09092019190600e84019060139082845b815481526020019060010190808311620082c35750505091909252505050606081015160e0820151610100909201519097919650945092505050565b60005462010000900460ff16156200832a57604051631785c68160e01b815260040160405180910390fd5b3360009081526001602052604090205460ff16156200835c5760405163b1d02c3d60e01b815260040160405180910390fd5b6200836662008f06565b62008373603f8262008ced565b620083915760405163056e881160e01b815260040160405180910390fd5b60006200839d62008f06565b6001600160a01b0381166000908152604160205260409020600c810154919250904290620083cf90610258906200a1ef565b1115620083ef57604051631f92cdbd60e11b815260040160405180910390fd5b60058101805462008400906200a156565b80601f01602080910402602001604051908101604052809291908181526020018280546200842e906200a156565b80156200847f5780601f1062008453576101008083540402835291602001916200847f565b820191906000526020600020905b8154815290600101906020018083116200846157829003601f168201915b50505082875250859160058401915081906200849c90826200a707565b5060208201516001820190620084b390826200a707565b5060408201516002820190620084ca90826200a707565b5060608201516003820190620084e190826200a707565b505042600c830155506040516001600160a01b038316907f85d6366b336ade7f106987ec7a8eac1e8799e508aeab045a39d2f63e0dc969d990600090a250505050565b60005462010000900460ff16156200854f57604051631785c68160e01b815260040160405180910390fd5b3360009081526001602052604090205460ff1615620085815760405163b1d02c3d60e01b815260040160405180910390fd5b828114620085a2576040516341abc80160e01b815260040160405180910390fd5b60005b83811015620086135762008600858583818110620085c757620085c76200a25a565b9050602002016020810190620085de9190620097c0565b848484818110620085f357620085f36200a25a565b9050602002013562009501565b6200860b816200a270565b9050620085a5565b5050505050565b6001600160a01b038082166000908152604160209081526040808320815161018081018352815486168152600182015486169381019390935260028101549094169082015260038301546060820152600483018054929384939091608084019162008685906200a156565b80601f0160208091040260200160405190810160405280929190818152602001828054620086b3906200a156565b8015620087045780601f10620086d85761010080835404028352916020019162008704565b820191906000526020600020905b815481529060010190602001808311620086e657829003601f168201915b50505050508152602001600582016040518060800160405290816000820180546200872f906200a156565b80601f01602080910402602001604051908101604052809291908181526020018280546200875d906200a156565b8015620087ae5780601f106200878257610100808354040283529160200191620087ae565b820191906000526020600020905b8154815290600101906020018083116200879057829003601f168201915b50505050508152602001600182018054620087c9906200a156565b80601f0160208091040260200160405190810160405280929190818152602001828054620087f7906200a156565b8015620088485780601f106200881c5761010080835404028352916020019162008848565b820191906000526020600020905b8154815290600101906020018083116200882a57829003601f168201915b5050505050815260200160028201805462008863906200a156565b80601f016020809104026020016040519081016040528092919081815260200182805462008891906200a156565b8015620088e25780601f10620088b657610100808354040283529160200191620088e2565b820191906000526020600020905b815481529060010190602001808311620088c457829003601f168201915b50505050508152602001600382018054620088fd906200a156565b80601f01602080910402602001604051908101604052809291908181526020018280546200892b906200a156565b80156200897c5780601f1062008950576101008083540402835291602001916200897c565b820191906000526020600020905b8154815290600101906020018083116200895e57829003601f168201915b505050919092525050508152604080516060808201835260098501546001600160401b038082168452600160401b82048116602080860191909152600160801b9092041683850152840191909152600a84015460ff16151582840152600b84015490830152600c8301546080830152600d8301546001600160a01b031660a0830152805161026081019182905260c09092019190600e84019060139082845b81548152602001906001019080831162008a1b5750505091909252505050604001519392505050565b600062008a53603f8462008ced565b62008a715760405163056e881160e01b815260040160405180910390fd5b6001600160a01b038381166000908152604160205260409081902060020154905163aa1966cd60e01b81526004810185905291169063aa1966cd9060240162005a98565b60005462010000900460ff161562008ae057604051631785c68160e01b815260040160405180910390fd5b3360009081526001602052604090205460ff161562008b125760405163b1d02c3d60e01b815260040160405180910390fd5b62008b1c62008f06565b62008b29603f8262008ced565b62008b475760405163056e881160e01b815260040160405180910390fd5b600062008b5362008f06565b905062008b64818787878762009220565b62008b8257604051631647e3cb60e11b815260040160405180910390fd5b60006001600160a01b03166045878760405162008ba19291906200a1a6565b908152604051908190036020019020546001600160a01b03161462008bd9576040516311fdb94760e01b815260040160405180910390fd5b6001600160a01b0381166000908152604160205260409020600c810154429062008c0790610258906200a1ef565b111562008c2757604051631f92cdbd60e11b815260040160405180910390fd5b4260468260040160405162008c3d91906200a7cf565b908152604051908190036020019020556004810162008c5e8789836200a3ba565b5042600c820155604051829060459062008c7c908a908a906200a1a6565b90815260405190819003602001812080546001600160a01b039384166001600160a01b0319909116179055908316907f783156582145bd0ff7924fae6953ba054cf1233eb60739a200ddb10de068ff0d9062008cdc908a908a906200a68b565b60405180910390a250505050505050565b6001600160a01b0381166000908152600183016020526040812054151562005adc565b6000806000848460405160200162008d2a9291906200a84d565b60408051601f1981840301815291815281516020928301206000818152604c9093529120549091504281111562008d6a57600080935093505050620026a7565b603e5462008d7990426200a1ef565b6000928352604c60205260409092208290555060019590945092505050565b6000600162008da8603f62009065565b62008db491906200a28c565b604954108015915062008e005760018301546040516001600160a01b03909116907f2afdc18061ac21cff7d9f11527ab9c8dec6fabd4edf6f894ed634bebd6a20d4590600090a2505050565b82600b015482111562008e1557600b83018290555b600a83015460ff166200649457600a8301805460ff191660019081179091556049805460009062008e489084906200a1ef565b909155505060018301546040516001600160a01b03909116907f4905ac32602da3fb8b4b7b00c285e5fc4c6c2308cc908b4a1e4e9625a29c90a390600090a2505050565b336000908152604360205260408120546001600160a01b03161580159062008ec1575033600090815260446020526040902054155b1562008ee45750336000908152604360205260409020546001600160a01b031690565b62008eee62008f06565b905090565b604e5460000362008f04576005604e555b565b336000908152604d60205260408120546001600160a01b03161562008f425750336000908152604d60205260409020546001600160a01b031690565b503390565b6001600160a01b0381166000908152604160205260409020600a81015460ff161562008f71575050565b6036546002820154604051630913db4760e01b81526001600160a01b03858116600483015290911690630913db4790602401602060405180830381865afa15801562008fc1573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019062008fe791906200a205565b1015620067ef576200900981603d54426200900391906200a1ef565b62008d98565b80546040516335409f7f60e01b81526001600160a01b039091166004820152611000906335409f7f90602401600060405180830381600087803b1580156200905057600080fd5b505af115801562006300573d6000803e3d6000fd5b600062005adf825490565b600062005adc8383620096db565b60008082905060038151108062009096575060098151115b15620090a55750600092915050565b604181600081518110620090bd57620090bd6200a25a565b016020015160f81c1080620090ef5750605a81600081518110620090e557620090e56200a25a565b016020015160f81c115b15620090fe5750600092915050565b60015b8151811015620092165760308282815181106200912257620091226200a25a565b016020015160f81c108062009153575060398282815181106200914957620091496200a25a565b016020015160f81c115b8015620091a3575060418282815181106200917257620091726200a25a565b016020015160f81c1080620091a35750605a8282815181106200919957620091996200a25a565b016020015160f81c115b8015620091f357506061828281518110620091c257620091c26200a25a565b016020015160f81c1080620091f35750607a828281518110620091e957620091e96200a25a565b016020015160f81c115b1562009203575060009392505050565b6200920e816200a270565b905062009101565b5060019392505050565b600060308414158062009234575060608214155b15620092435750600062009347565b6000868686466040516020016200925e94939291906200a897565b60408051808303601f1901815282825280516020918201208184528383019092529092506000919060208201818036833701905050905081602082015260008186868a8a604051602001620092b89594939291906200a8c4565b60408051808303601f190181526001808452838301909252925060009190602082018180368337019050509050815160016020830182602086016066600019fa6200930257600080fd5b506000816000815181106200931b576200931b6200a25a565b016020015160f81c9050600181146200933d5760009550505050505062009347565b6001955050505050505b95945050505050565b60008061200361dead60405162009367906200977a565b6001600160a01b03928316815291166020820152606060408201819052600090820152608001604051809103906000f080158015620093aa573d6000803e3d6000fd5b509050806001600160a01b031663f399e22e3486866040518463ffffffff1660e01b8152600401620093de9291906200a8fc565b6000604051808303818588803b158015620093f857600080fd5b505af11580156200940d573d6000803e3d6000fd5b50506040516001600160a01b038086169450881692507fd481492e4e93bb36b4c12a5af93f03be3bf04b454dfbc35dd2663fa26f44d5b09150600090a39392505050565b600062005adc836001600160a01b03841662009708565b600054610100900460ff16620094d55760405162461bcd60e51b815260206004820152602b60248201527f496e697469616c697a61626c653a20636f6e7472616374206973206e6f74206960448201526a6e697469616c697a696e6760a81b6064820152608401620012e3565b600080546001600160a01b039092166301000000026301000000600160b81b0319909216919091179055565b816200950f603f8262008ced565b6200952d5760405163056e881160e01b815260040160405180910390fd5b6001600160a01b03838116600090815260416020526040808220600201549051635569f64b60e11b8152336004820152602481018690529192169063aad3ec96906044016020604051808303816000875af115801562009591573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190620095b791906200a205565b9050336001600160a01b0316846001600160a01b03167ff7a40077ff7a04c7e61f6f26fb13774259ddf1b6bce9ecf26a8276cdd399268383604051620095ff91815260200190565b60405180910390a350505050565b6000816040516020016200962291906200a922565b60405160208183030381529060405280519060200120836040516020016200964b91906200a922565b6040516020818303038152906040528051906020012014905092915050565b015190565b600080546040516001600160a01b0380851693630100000090930416917f44fc1b38a4abaa91ebd1b628a5b259a698f86238c8217d68f516e87769c60c0b91a3600080546001600160a01b039092166301000000026301000000600160b81b0319909216919091179055565b6000826000018281548110620096f557620096f56200a25a565b9060005260206000200154905092915050565b6000818152600183016020526040812054620097515750815460018181018455600084815260208082209093018490558454848252828601909352604090209190915562005adf565b50600062005adf565b50805460008255906000526020600020908101906200190e919062009788565b610e96806200a94183390190565b5b808211156200979f576000815560010162009789565b5090565b80356001600160a01b0381168114620097bb57600080fd5b919050565b600060208284031215620097d357600080fd5b62005adc82620097a3565b60008083601f840112620097f157600080fd5b5081356001600160401b038111156200980957600080fd5b602083019150836020828501011115620026a757600080fd5b600080602083850312156200983657600080fd5b82356001600160401b038111156200984d57600080fd5b6200985b85828601620097de565b90969095509350505050565b6000806000604084860312156200987d57600080fd5b833560ff811681146200988f57600080fd5b925060208401356001600160401b03811115620098ab57600080fd5b620098b986828701620097de565b9497909650939450505050565b60005b83811015620098e3578181015183820152602001620098c9565b50506000910152565b6000815180845262009906816020860160208601620098c6565b601f01601f19169290920160200192915050565b60208152600062005adc6020830184620098ec565b634e487b7160e01b600052604160045260246000fd5b604051608081016001600160401b03811182821017156200996a576200996a6200992f565b60405290565b60006001600160401b03808411156200998d576200998d6200992f565b604051601f8501601f19908116603f01168101908282118183101715620099b857620099b86200992f565b81604052809350858152868686011115620099d257600080fd5b858560208301376000602087830101525050509392505050565b600060208284031215620099ff57600080fd5b81356001600160401b0381111562009a1657600080fd5b8201601f8101841362009a2857600080fd5b62009a398482356020840162009970565b949350505050565b60008083601f84011262009a5457600080fd5b5081356001600160401b0381111562009a6c57600080fd5b6020830191508360208260051b8501011115620026a757600080fd5b6000806020838503121562009a9c57600080fd5b82356001600160401b0381111562009ab357600080fd5b6200985b8582860162009a41565b600081518084526020808501945080840160005b8381101562009afc5781516001600160a01b03168752958201959082019060010162009ad5565b509495945050505050565b60408152600062009b1c604083018562009ac1565b6020838203818501528185518084528284019150828160051b8501018388016000805b8481101562009b9657878403601f19018652825180518086529088019088860190845b8181101562009b805783518352928a0192918a019160010162009b62565b5050968801969450509186019160010162009b3f565b50919a9950505050505050505050565b6000806040838503121562009bba57600080fd5b62009bc583620097a3565b946020939093013593505050565b80358015158114620097bb57600080fd5b6000806000806080858703121562009bfb57600080fd5b62009c0685620097a3565b935062009c1660208601620097a3565b92506040850135915062009c2d6060860162009bd3565b905092959194509250565b6001600160401b03811681146200190e57600080fd5b60006020828403121562009c6157600080fd5b813562009c6e8162009c38565b9392505050565b6000806040838503121562009c8957600080fd5b50508035926020909101359150565b60808152600062009cad608083018762009ac1565b82810360208481019190915286518083528782019282019060005b8181101562009ce65784518352938301939183019160010162009cc8565b5050848103604086015286518082528282019350600581901b8201830183890160005b8381101562009d3b57601f1985840301875262009d28838351620098ec565b9686019692509085019060010162009d09565b5050809550505050505082606083015295945050505050565b600080600080600080600087890360e081121562009d7157600080fd5b62009d7c89620097a3565b975060208901356001600160401b038082111562009d9957600080fd5b62009da78c838d01620097de565b909950975060408b013591508082111562009dc157600080fd5b62009dcf8c838d01620097de565b90975095508591506060605f198401121562009dea57600080fd5b60608b01945060c08b013592508083111562009e0557600080fd5b505088016080818b03121562009e1a57600080fd5b8091505092959891949750929550565b6000806040838503121562009e3e57600080fd5b62009e4983620097a3565b915062009e596020840162009bd3565b90509250929050565b60208152600082516080602084015262009e8060a0840182620098ec565b90506020840151601f198085840301604086015262009ea08383620098ec565b9250604086015191508085840301606086015262009ebf8383620098ec565b9250606086015191508085840301608086015250620093478282620098ec565b6000806000806040858703121562009ef657600080fd5b84356001600160401b038082111562009f0e57600080fd5b62009f1c88838901620097de565b9096509450602087013591508082111562009f3657600080fd5b5062009f4587828801620097de565b95989497509550505050565b60008060006040848603121562009f6757600080fd5b83356001600160401b0381111562009f7e57600080fd5b62009f8c8682870162009a41565b909450925062009fa1905060208501620097a3565b90509250925092565b60608152600062009fbf606083018662009ac1565b828103602084015262009fd3818662009ac1565b915050826040830152949350505050565b600082601f83011262009ff657600080fd5b62005adc8383356020850162009970565b6000602082840312156200a01a57600080fd5b81356001600160401b03808211156200a03257600080fd5b90830190608082860312156200a04757600080fd5b6200a05162009945565b8235828111156200a06157600080fd5b6200a06f8782860162009fe4565b8252506020830135828111156200a08557600080fd5b6200a0938782860162009fe4565b6020830152506040830135828111156200a0ac57600080fd5b6200a0ba8782860162009fe4565b6040830152506060830135828111156200a0d357600080fd5b6200a0e18782860162009fe4565b60608301525095945050505050565b600080600080604085870312156200a10757600080fd5b84356001600160401b03808211156200a11f57600080fd5b6200a12d8883890162009a41565b909650945060208701359150808211156200a14757600080fd5b5062009f458782880162009a41565b600181811c908216806200a16b57607f821691505b602082108103620020d957634e487b7160e01b600052602260045260246000fd5b6001600160a01b0392831681529116602082015260400190565b8183823760009101908152919050565b634e487b7160e01b600052601160045260246000fd5b6000826200a1ea57634e487b7160e01b600052601260045260246000fd5b500490565b8082018082111562005adf5762005adf6200a1b6565b6000602082840312156200a21857600080fd5b5051919050565b8381526020810183905260608101600383106200a24c57634e487b7160e01b600052602160045260246000fd5b826040830152949350505050565b634e487b7160e01b600052603260045260246000fd5b6000600182016200a285576200a2856200a1b6565b5060010190565b8181038181111562005adf5762005adf6200a1b6565b808202811582820484141762005adf5762005adf6200a1b6565b6040815260006200a2d1604083018562009ac1565b905060018060a01b03831660208301529392505050565b6001600160401b038281168282160390808211156200a30b576200a30b6200a1b6565b5092915050565b6000808335601e198436030181126200a32a57600080fd5b8301803591506001600160401b038211156200a34557600080fd5b602001915036819003821315620026a757600080fd5b601f8211156200649457600081815260208120601f850160051c810160208610156200a3845750805b601f850160051c820191505b8181101562006300578281556001016200a390565b600019600383901b1c191660019190911b1790565b6001600160401b038311156200a3d4576200a3d46200992f565b6200a3ec836200a3e583546200a156565b836200a35b565b6000601f8411600181146200a41f57600085156200a40a5750838201355b6200a41686826200a3a5565b84555062008613565b600083815260209020601f19861690835b828110156200a45257868501358255602094850194600190920191016200a430565b50868210156200a4705760001960f88860031b161c19848701351681555b505060018560011b0183555050505050565b6200a48e82836200a312565b6001600160401b038111156200a4a8576200a4a86200992f565b6200a4c0816200a4b985546200a156565b856200a35b565b6000601f8211600181146200a4f357600083156200a4de5750838201355b6200a4ea84826200a3a5565b8655506200a550565b600085815260209020601f19841690835b828110156200a52657868501358255602094850194600190920191016200a504565b50848210156200a5445760001960f88660031b161c19848701351681555b505060018360011b0185555b505050506200a56360208301836200a312565b6200a5738183600186016200a3ba565b50506200a58460408301836200a312565b6200a5948183600286016200a3ba565b50506200a5a560608301836200a312565b6200a5b58183600386016200a3ba565b50505050565b81356200a5c88162009c38565b6001600160401b03811690508154816001600160401b0319821617835560208401356200a5f58162009c38565b6fffffffffffffffff0000000000000000604091821b166fffffffffffffffffffffffffffffffff198316841781178555908501356200a6358162009c38565b6001600160c01b0319929092169092179190911760809190911b67ffffffffffffffff60801b1617905550565b81835281816020850137506000828201602090810191909152601f909101601f19169091010190565b60208152600062009a396020830184866200a662565b634e487b7160e01b600052603160045260246000fd5b6000816200a6c9576200a6c96200a1b6565b506000190190565b6040815260006200a6e76040830186886200a662565b82810360208401526200a6fc8185876200a662565b979650505050505050565b81516001600160401b038111156200a723576200a7236200992f565b6200a73b816200a73484546200a156565b846200a35b565b602080601f8311600181146200a76f57600084156200a75a5750858301515b6200a76685826200a3a5565b86555062006300565b600085815260208120601f198616915b828110156200a7a0578886015182559484019460019091019084016200a77f565b50858210156200a7bf5787850151600019600388901b60f8161c191681555b5050505050600190811b01905550565b60008083546200a7df816200a156565b600182811680156200a7fa57600181146200a810576200a841565b60ff19841687528215158302870194506200a841565b8760005260208060002060005b858110156200a8385781548a8201529084019082016200a81d565b50505082870194505b50929695505050505050565b6bffffffffffffffffffffffff198360601b1681526000600383106200a88357634e487b7160e01b600052602160045260246000fd5b5060f89190911b6014820152601501919050565b6bffffffffffffffffffffffff198560601b16815282846014830137601492019182015260340192915050565b600086516200a8d8818460208b01620098c6565b82018587823760009086019081528385823760009301928352509095945050505050565b6001600160a01b038316815260406020820181905260009062009a3990830184620098ec565b600082516200a936818460208701620098c6565b919091019291505056fe608060405260405162000e9638038062000e96833981016040819052620000269162000497565b828162000036828260006200004d565b50620000449050826200008a565b505050620005ca565b6200005883620000e5565b600082511180620000665750805b1562000085576200008383836200012760201b620001691760201c565b505b505050565b7f7e644d79422f17c01e4894b5f4f588d331ebfa28653d42ae832dc59e38c9798f620000b562000156565b604080516001600160a01b03928316815291841660208301520160405180910390a1620000e2816200018f565b50565b620000f08162000244565b6040516001600160a01b038216907fbc7cd75a20ee27fd9adebab32041f755214dbc6bffa90cc0225b39da2e5c2d3b90600090a250565b60606200014f838360405180606001604052806027815260200162000e6f60279139620002f8565b9392505050565b60006200018060008051602062000e4f83398151915260001b6200037760201b620001951760201c565b546001600160a01b0316919050565b6001600160a01b038116620001fa5760405162461bcd60e51b815260206004820152602660248201527f455243313936373a206e65772061646d696e20697320746865207a65726f206160448201526564647265737360d01b60648201526084015b60405180910390fd5b806200022360008051602062000e4f83398151915260001b6200037760201b620001951760201c565b80546001600160a01b0319166001600160a01b039290921691909117905550565b6200025a816200037a60201b620001981760201c565b620002be5760405162461bcd60e51b815260206004820152602d60248201527f455243313936373a206e657720696d706c656d656e746174696f6e206973206e60448201526c1bdd08184818dbdb9d1c9858dd609a1b6064820152608401620001f1565b80620002237f360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc60001b6200037760201b620001951760201c565b6060600080856001600160a01b03168560405162000317919062000577565b600060405180830381855af49150503d806000811462000354576040519150601f19603f3d011682016040523d82523d6000602084013e62000359565b606091505b5090925090506200036d8683838762000389565b9695505050505050565b90565b6001600160a01b03163b151590565b60608315620003fd578251600003620003f5576001600160a01b0385163b620003f55760405162461bcd60e51b815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e74726163740000006044820152606401620001f1565b508162000409565b62000409838362000411565b949350505050565b815115620004225781518083602001fd5b8060405162461bcd60e51b8152600401620001f1919062000595565b80516001600160a01b03811681146200045657600080fd5b919050565b634e487b7160e01b600052604160045260246000fd5b60005b838110156200048e57818101518382015260200162000474565b50506000910152565b600080600060608486031215620004ad57600080fd5b620004b8846200043e565b9250620004c8602085016200043e565b60408501519092506001600160401b0380821115620004e657600080fd5b818601915086601f830112620004fb57600080fd5b8151818111156200051057620005106200045b565b604051601f8201601f19908116603f011681019083821181831017156200053b576200053b6200045b565b816040528281528960208487010111156200055557600080fd5b6200056883602083016020880162000471565b80955050505050509250925092565b600082516200058b81846020870162000471565b9190910192915050565b6020815260008251806020840152620005b681604085016020870162000471565b601f01601f19169190910160400192915050565b61087580620005da6000396000f3fe60806040523661001357610011610017565b005b6100115b61001f6101a7565b6001600160a01b0316330361015f5760606001600160e01b0319600035166364d3180d60e11b810161005a576100536101da565b9150610157565b63587086bd60e11b6001600160e01b031982160161007a57610053610231565b63070d7c6960e41b6001600160e01b031982160161009a57610053610277565b621eb96f60e61b6001600160e01b03198216016100b9576100536102a8565b63a39f25e560e01b6001600160e01b03198216016100d9576100536102e8565b60405162461bcd60e51b815260206004820152604260248201527f5472616e73706172656e745570677261646561626c6550726f78793a2061646d60448201527f696e2063616e6e6f742066616c6c6261636b20746f2070726f78792074617267606482015261195d60f21b608482015260a4015b60405180910390fd5b815160208301f35b6101676102fc565b565b606061018e83836040518060600160405280602781526020016108426027913961030c565b9392505050565b90565b6001600160a01b03163b151590565b60007fb53127684a568b3173ae13b9f8a6016e243e63b6e8ee1178d6a717850b5d61035b546001600160a01b0316919050565b60606101e4610384565b60006101f33660048184610695565b81019061020091906106db565b905061021d8160405180602001604052806000815250600061038f565b505060408051602081019091526000815290565b60606000806102433660048184610695565b810190610250919061070c565b915091506102608282600161038f565b604051806020016040528060008152509250505090565b6060610281610384565b60006102903660048184610695565b81019061029d91906106db565b905061021d816103bb565b60606102b2610384565b60006102bc6101a7565b604080516001600160a01b03831660208201529192500160405160208183030381529060405291505090565b60606102f2610384565b60006102bc610412565b610167610307610412565b610421565b6060600080856001600160a01b03168560405161032991906107f2565b600060405180830381855af49150503d8060008114610364576040519150601f19603f3d011682016040523d82523d6000602084013e610369565b606091505b509150915061037a86838387610445565b9695505050505050565b341561016757600080fd5b610398836104c6565b6000825111806103a55750805b156103b6576103b48383610169565b505b505050565b7f7e644d79422f17c01e4894b5f4f588d331ebfa28653d42ae832dc59e38c9798f6103e46101a7565b604080516001600160a01b03928316815291841660208301520160405180910390a161040f81610506565b50565b600061041c6105af565b905090565b3660008037600080366000845af43d6000803e808015610440573d6000f35b3d6000fd5b606083156104b45782516000036104ad576001600160a01b0385163b6104ad5760405162461bcd60e51b815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e7472616374000000604482015260640161014e565b50816104be565b6104be83836105d7565b949350505050565b6104cf81610601565b6040516001600160a01b038216907fbc7cd75a20ee27fd9adebab32041f755214dbc6bffa90cc0225b39da2e5c2d3b90600090a250565b6001600160a01b03811661056b5760405162461bcd60e51b815260206004820152602660248201527f455243313936373a206e65772061646d696e20697320746865207a65726f206160448201526564647265737360d01b606482015260840161014e565b807fb53127684a568b3173ae13b9f8a6016e243e63b6e8ee1178d6a717850b5d61035b80546001600160a01b0319166001600160a01b039290921691909117905550565b60007f360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc6101cb565b8151156105e75781518083602001fd5b8060405162461bcd60e51b815260040161014e919061080e565b6001600160a01b0381163b61066e5760405162461bcd60e51b815260206004820152602d60248201527f455243313936373a206e657720696d706c656d656e746174696f6e206973206e60448201526c1bdd08184818dbdb9d1c9858dd609a1b606482015260840161014e565b807f360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc61058e565b600080858511156106a557600080fd5b838611156106b257600080fd5b5050820193919092039150565b80356001600160a01b03811681146106d657600080fd5b919050565b6000602082840312156106ed57600080fd5b61018e826106bf565b634e487b7160e01b600052604160045260246000fd5b6000806040838503121561071f57600080fd5b610728836106bf565b9150602083013567ffffffffffffffff8082111561074557600080fd5b818501915085601f83011261075957600080fd5b81358181111561076b5761076b6106f6565b604051601f8201601f19908116603f01168101908382118183101715610793576107936106f6565b816040528281528860208487010111156107ac57600080fd5b8260208601602083013760006020848301015280955050505050509250929050565b60005b838110156107e95781810151838201526020016107d1565b50506000910152565b600082516108048184602087016107ce565b9190910192915050565b602081526000825180602084015261082d8160408501602087016107ce565b601f01601f1916919091016040019291505056fe416464726573733a206c6f772d6c6576656c2064656c65676174652063616c6c206661696c6564a164736f6c6343000811000ab53127684a568b3173ae13b9f8a6016e243e63b6e8ee1178d6a717850b5d6103416464726573733a206c6f772d6c6576656c2064656c65676174652063616c6c206661696c6564a164736f6c6343000811000a \ No newline at end of file diff --git a/core/systemcontracts/pasteur/types.go b/core/systemcontracts/pasteur/types.go new file mode 100644 index 0000000000..34c2b67cb2 --- /dev/null +++ b/core/systemcontracts/pasteur/types.go @@ -0,0 +1,30 @@ +package pasteur + +import _ "embed" + +// contract codes for Mainnet upgrade +var ( + //go:embed mainnet/StakeHubContract + MainnetStakeHubContract string + + //go:embed mainnet/GovernorContract + MainnetGovernorContract string +) + +// contract codes for Chapel upgrade +var ( + //go:embed chapel/StakeHubContract + ChapelStakeHubContract string + + //go:embed chapel/GovernorContract + ChapelGovernorContract string +) + +// contract codes for Rialto upgrade +var ( + //go:embed rialto/StakeHubContract + RialtoStakeHubContract string + + //go:embed rialto/GovernorContract + RialtoGovernorContract string +) diff --git a/core/systemcontracts/upgrade.go b/core/systemcontracts/upgrade.go index 0ef6eef11c..825c15a2dc 100644 --- a/core/systemcontracts/upgrade.go +++ b/core/systemcontracts/upgrade.go @@ -24,6 +24,7 @@ import ( "github.com/ethereum/go-ethereum/core/systemcontracts/moran" "github.com/ethereum/go-ethereum/core/systemcontracts/niels" "github.com/ethereum/go-ethereum/core/systemcontracts/pascal" + "github.com/ethereum/go-ethereum/core/systemcontracts/pasteur" "github.com/ethereum/go-ethereum/core/systemcontracts/planck" "github.com/ethereum/go-ethereum/core/systemcontracts/plato" "github.com/ethereum/go-ethereum/core/systemcontracts/ramanujan" @@ -95,6 +96,8 @@ var ( maxwellUpgrade = make(map[string]*Upgrade) fermiUpgrade = make(map[string]*Upgrade) + + pasteurUpgrade = make(map[string]*Upgrade) ) func init() { @@ -1055,6 +1058,54 @@ func init() { }, }, } + + pasteurUpgrade[mainNet] = &Upgrade{ + UpgradeName: "pasteur", + Configs: []*UpgradeConfig{ + { + ContractAddr: common.HexToAddress(StakeHubContract), + CommitUrl: "https://github.com/bnb-chain/bsc-genesis-contract/commit/041881a02475638b19f3d840871b7621cdebd8f8", + Code: pasteur.MainnetStakeHubContract, + }, + { + ContractAddr: common.HexToAddress(GovernorContract), + CommitUrl: "https://github.com/bnb-chain/bsc-genesis-contract/commit/041881a02475638b19f3d840871b7621cdebd8f8", + Code: pasteur.MainnetGovernorContract, + }, + }, + } + + pasteurUpgrade[chapelNet] = &Upgrade{ + UpgradeName: "pasteur", + Configs: []*UpgradeConfig{ + { + ContractAddr: common.HexToAddress(StakeHubContract), + CommitUrl: "https://github.com/bnb-chain/bsc-genesis-contract/commit/041881a02475638b19f3d840871b7621cdebd8f8", + Code: pasteur.ChapelStakeHubContract, + }, + { + ContractAddr: common.HexToAddress(GovernorContract), + CommitUrl: "https://github.com/bnb-chain/bsc-genesis-contract/commit/041881a02475638b19f3d840871b7621cdebd8f8", + Code: pasteur.ChapelGovernorContract, + }, + }, + } + + pasteurUpgrade[rialtoNet] = &Upgrade{ + UpgradeName: "pasteur", + Configs: []*UpgradeConfig{ + { + ContractAddr: common.HexToAddress(StakeHubContract), + CommitUrl: "https://github.com/bnb-chain/bsc-genesis-contract/commit/041881a02475638b19f3d840871b7621cdebd8f8", + Code: pasteur.RialtoStakeHubContract, + }, + { + ContractAddr: common.HexToAddress(GovernorContract), + CommitUrl: "https://github.com/bnb-chain/bsc-genesis-contract/commit/041881a02475638b19f3d840871b7621cdebd8f8", + Code: pasteur.RialtoGovernorContract, + }, + }, + } } func TryUpdateBuildInSystemContract(config *params.ChainConfig, blockNumber *big.Int, lastBlockTime uint64, blockTime uint64, statedb vm.StateDB, atBlockBegin bool) { @@ -1174,6 +1225,10 @@ func upgradeBuildInSystemContract(config *params.ChainConfig, blockNumber *big.I applySystemContractUpgrade(fermiUpgrade[network], blockNumber, statedb, logger) } + if config.IsOnPasteur(blockNumber, lastBlockTime, blockTime) { + applySystemContractUpgrade(pasteurUpgrade[network], blockNumber, statedb, logger) + } + /* apply other upgrades */ diff --git a/core/tracing/journal.go b/core/tracing/journal.go index 62a70d6c27..560c937115 100644 --- a/core/tracing/journal.go +++ b/core/tracing/journal.go @@ -155,10 +155,18 @@ func (j *journal) OnBalanceChange(addr common.Address, prev, new *big.Int, reaso } func (j *journal) OnNonceChangeV2(addr common.Address, prev, new uint64, reason NonceChangeReason) { - // When a contract is created, the nonce of the creator is incremented. - // This change is not reverted when the creation fails. - if reason != NonceChangeContractCreator { - j.entries = append(j.entries, nonceChange{addr: addr, prev: prev, new: new}) + j.entries = append(j.entries, nonceChange{addr: addr, prev: prev, new: new}) + if reason == NonceChangeContractCreator { + // When a contract is created via CREATE/CREATE2, the creator's nonce is + // incremented. The EVM does not revert this when the CREATE frame itself + // fails (the nonce change happens before the EVM snapshot). However, if + // a parent frame reverts, the nonce must be reverted along with everything + // else. + // + // To achieve this, advance the current frame's revision point past this + // entry. The CREATE frame's revert won't touch it (it's below the revision), + // but a parent frame's revert will (it's above the parent's revision). + j.revisions[len(j.revisions)-1] = len(j.entries) } if j.hooks.OnNonceChangeV2 != nil { j.hooks.OnNonceChangeV2(addr, prev, new, reason) diff --git a/core/tracing/journal_test.go b/core/tracing/journal_test.go index e00447f5f3..488d192502 100644 --- a/core/tracing/journal_test.go +++ b/core/tracing/journal_test.go @@ -219,6 +219,42 @@ func TestNonceIncOnCreate(t *testing.T) { } } +// TestNonceIncOnCreateParentReverts checks that the creator's nonce increment +// from CREATE survives the CREATE frame's own revert but is properly reverted +// when the parent call frame reverts. +func TestNonceIncOnCreateParentReverts(t *testing.T) { + const opCREATE = 0xf0 + + tr := &testTracer{t: t} + wr, err := WrapWithJournal(&Hooks{OnNonceChange: tr.OnNonceChange}) + if err != nil { + t.Fatalf("failed to wrap test tracer: %v", err) + } + + addr := common.HexToAddress("0x1234") + { + // Parent call frame + wr.OnEnter(0, 0, addr, addr, nil, 1000, big.NewInt(0)) + { + // CREATE frame — creator nonce incremented, then CREATE reverts + wr.OnEnter(1, opCREATE, addr, addr, nil, 1000, big.NewInt(0)) + wr.OnNonceChangeV2(addr, 0, 1, NonceChangeContractCreator) + wr.OnExit(1, nil, 100, errors.New("revert"), true) + } + // After CREATE reverts, nonce should still be 1 + if tr.nonce != 1 { + t.Fatalf("nonce after CREATE revert: got %v, want 1", tr.nonce) + } + // Parent frame also reverts + wr.OnExit(0, nil, 150, errors.New("revert"), true) + } + + // After parent reverts, nonce should be back to 0 + if tr.nonce != 0 { + t.Fatalf("nonce after parent revert: got %v, want 0", tr.nonce) + } +} + func TestOnNonceChangeV2(t *testing.T) { tr := &testTracer{t: t} wr, err := WrapWithJournal(&Hooks{OnNonceChangeV2: tr.OnNonceChangeV2}) diff --git a/core/txpool/blobpool/blobpool.go b/core/txpool/blobpool/blobpool.go index 06f94354d9..521a2697ec 100644 --- a/core/txpool/blobpool/blobpool.go +++ b/core/txpool/blobpool/blobpool.go @@ -344,7 +344,6 @@ type BlobPool struct { head atomic.Pointer[types.Header] // Current head of the chain state *state.StateDB // Current state at the head of the chain gasTip atomic.Pointer[uint256.Int] // Currently accepted minimum gas tip - maxGas atomic.Uint64 // Currently accepted max gas, it will be modified by MinerAPI lookup *lookup // Lookup table mapping blobs to txs and txs to billy entries index map[common.Address][]*blobTxMeta // Blob transactions grouped by accounts, sorted by nonce @@ -1335,7 +1334,6 @@ func (p *BlobPool) ValidateTxBasics(tx *types.Transaction) error { MaxSize: txMaxSize, MinTip: p.gasTip.Load().ToBig(), MaxBlobCount: maxBlobsPerTx, - MaxGas: p.GetMaxGas(), } return txpool.ValidateTransaction(tx, p.head.Load(), p.signer, opts) } @@ -2159,14 +2157,6 @@ func (p *BlobPool) Status(hash common.Hash) txpool.TxStatus { return txpool.TxStatusUnknown } -func (p *BlobPool) SetMaxGas(maxGas uint64) { - p.maxGas.Store(maxGas) -} - -func (p *BlobPool) GetMaxGas() uint64 { - return p.maxGas.Load() -} - // Clear implements txpool.SubPool, removing all tracked transactions // from the blob pool and persistent store. // diff --git a/core/txpool/legacypool/legacypool.go b/core/txpool/legacypool/legacypool.go index 50f9cf4eb4..7f77e62004 100644 --- a/core/txpool/legacypool/legacypool.go +++ b/core/txpool/legacypool/legacypool.go @@ -19,7 +19,6 @@ package legacypool import ( "errors" - "fmt" "maps" "math" "math/big" @@ -115,10 +114,9 @@ var ( // that this number is pretty low, since txpool reorgs happen very frequently. dropBetweenReorgHistogram = metrics.NewRegisteredHistogram("txpool/dropbetweenreorg", nil, metrics.NewExpDecaySample(1028, 0.015)) - pendingGauge = metrics.NewRegisteredGauge("txpool/pending", nil) - queuedGauge = metrics.NewRegisteredGauge("txpool/queued", nil) - slotsGauge = metrics.NewRegisteredGauge("txpool/slots", nil) - OverflowPoolGauge = metrics.NewRegisteredGauge("txpool/overflowpool", nil) + pendingGauge = metrics.NewRegisteredGauge("txpool/pending", nil) + queuedGauge = metrics.NewRegisteredGauge("txpool/queued", nil) + slotsGauge = metrics.NewRegisteredGauge("txpool/slots", nil) reheapTimer = metrics.NewRegisteredTimer("txpool/reheap", nil) ) @@ -149,11 +147,10 @@ type Config struct { PriceLimit uint64 // Minimum gas price to enforce for acceptance into the pool PriceBump uint64 // Minimum price bump percentage to replace an already existing transaction (nonce) - AccountSlots uint64 // Number of executable transaction slots guaranteed per account - GlobalSlots uint64 // Maximum number of executable transaction slots for all accounts - AccountQueue uint64 // Maximum number of non-executable transaction slots permitted per account - GlobalQueue uint64 // Maximum number of non-executable transaction slots for all accounts - OverflowPoolSlots uint64 // Maximum number of transaction slots in overflow pool + AccountSlots uint64 // Number of executable transaction slots guaranteed per account + GlobalSlots uint64 // Maximum number of executable transaction slots for all accounts + AccountQueue uint64 // Maximum number of non-executable transaction slots permitted per account + GlobalQueue uint64 // Maximum number of non-executable transaction slots for all accounts Lifetime time.Duration // Maximum amount of time non-executable transaction are queued ReannounceTime time.Duration // Duration for announcing local pending transactions again @@ -167,11 +164,10 @@ var DefaultConfig = Config{ PriceLimit: 1, PriceBump: 10, - AccountSlots: 200, - GlobalSlots: 8000, - AccountQueue: 200, - GlobalQueue: 4000, - OverflowPoolSlots: 0, + AccountSlots: 200, + GlobalSlots: 8000, + AccountQueue: 200, + GlobalQueue: 4000, Lifetime: 3 * time.Hour, ReannounceTime: 10 * 365 * 24 * time.Hour, @@ -247,7 +243,6 @@ type LegacyPool struct { scope event.SubscriptionScope signer types.Signer mu sync.RWMutex - maxGas atomic.Uint64 // Currently accepted max gas, it will be modified by MinerAPI currentHead atomic.Pointer[types.Header] // Current head of the blockchain currentState *state.StateDB // Current state in the blockchain head @@ -259,8 +254,6 @@ type LegacyPool struct { all *lookup // All transactions to allow lookups priced *pricedList // All transactions sorted by price - localBufferPool *TxOverflowPool // Local buffer transactions - reqResetCh chan *txpoolResetRequest reqPromoteCh chan *accountSet queueTxEventCh chan *types.Transaction @@ -298,7 +291,6 @@ func New(config Config, chain BlockChain) *LegacyPool { reorgDoneCh: make(chan chan struct{}), reorgShutdownCh: make(chan struct{}), initDoneCh: make(chan struct{}), - localBufferPool: NewTxOverflowPoolHeap(config.OverflowPoolSlots), } pool.priced = newPricedList(pool.all) @@ -494,17 +486,6 @@ func (pool *LegacyPool) Stats() (int, int) { return pool.stats() } -func (pool *LegacyPool) statsOverflowPool() uint64 { - pool.mu.RLock() - defer pool.mu.RUnlock() - - if pool.localBufferPool == nil { - return 0 - } - - return pool.localBufferPool.Size() -} - // stats retrieves the current pool stats, namely the number of pending and the // number of queued (non-executable) transactions. func (pool *LegacyPool) stats() (int, int) { @@ -623,7 +604,6 @@ func (pool *LegacyPool) ValidateTxBasics(tx *types.Transaction) error { 1<= maxMainPoolSize { - return - } - - extraSlots := maxMainPoolSize - currentMainPoolSize - extraTransactions := (extraSlots + 3) / 4 // Since a transaction can take up to 4 slots - log.Debug("Will attempt to transfer from OverflowPool to MainPool", "transactions", extraTransactions) - txs := pool.localBufferPool.Flush(extraTransactions) - if len(txs) == 0 { - return - } - - pool.Add(txs, false) -} - -func (pool *LegacyPool) PrintTxStats() { - for _, l := range pool.pending { - for _, transaction := range l.txs.items { - from, _ := types.Sender(pool.signer, transaction) - fmt.Println("from: ", from, " Pending:", transaction.Hash().String(), transaction.GasFeeCap(), transaction.GasTipCap()) - } - } - - pool.localBufferPool.PrintTxStats() - fmt.Println("length of all: ", pool.all.Slots()) - fmt.Println("----------------------------------------------------") -} - // Clear implements txpool.SubPool, removing all tracked txs from the pool // and rotating the journal. // diff --git a/core/txpool/legacypool/legacypool_test.go b/core/txpool/legacypool/legacypool_test.go index ddae5d441b..51796b565d 100644 --- a/core/txpool/legacypool/legacypool_test.go +++ b/core/txpool/legacypool/legacypool_test.go @@ -41,7 +41,6 @@ import ( "github.com/ethereum/go-ethereum/params" "github.com/ethereum/go-ethereum/trie" "github.com/holiman/uint256" - "gotest.tools/assert" ) var ( @@ -1634,7 +1633,6 @@ func TestRepricingDynamicFee(t *testing.T) { // Note, local transactions are never allowed to be dropped. func TestUnderpricing(t *testing.T) { t.Parallel() - testTxPoolConfig.OverflowPoolSlots = 5 // Create the pool to test the pricing enforcement with statedb, _ := state.New(types.EmptyRootHash, state.NewDatabaseForTesting()) @@ -1800,8 +1798,6 @@ func TestUnderpricingDynamicFee(t *testing.T) { pool.config.GlobalSlots = 2 pool.config.GlobalQueue = 2 - pool.config.OverflowPoolSlots = 0 - // Keep track of transaction events to ensure all executables get announced events := make(chan core.NewTxsEvent, 32) sub := pool.txFeed.Subscribe(events) @@ -1879,7 +1875,6 @@ func TestUnderpricingDynamicFee(t *testing.T) { func TestDualHeapEviction(t *testing.T) { t.Parallel() - testTxPoolConfig.OverflowPoolSlots = 1 pool, _ := setupPoolWithConfig(eip1559Config) defer pool.Close() @@ -1889,7 +1884,6 @@ func TestDualHeapEviction(t *testing.T) { // With pool size = 20, floatingCount = 20 * 1 / 5 = 4, which is sufficient. pool.config.GlobalSlots = 10 pool.config.GlobalQueue = 10 - pool.config.OverflowPoolSlots = 1 var ( highTip, highCap *types.Transaction @@ -2092,51 +2086,6 @@ func TestReplacement(t *testing.T) { } } -func TestTransferTransactions(t *testing.T) { - t.Parallel() - testTxPoolConfig.OverflowPoolSlots = 1 - pool, _ := setupPoolWithConfig(eip1559Config) - defer pool.Close() - - pool.config.GlobalSlots = 1 - pool.config.GlobalQueue = 2 - - // Create a number of test accounts and fund them - keys := make([]*ecdsa.PrivateKey, 5) - for i := 0; i < len(keys); i++ { - keys[i], _ = crypto.GenerateKey() - testAddBalance(pool, crypto.PubkeyToAddress(keys[i].PublicKey), big.NewInt(1000000)) - } - - tx := dynamicFeeTx(0, 100000, big.NewInt(3), big.NewInt(2), keys[0]) - from, _ := types.Sender(pool.signer, tx) - pool.addToOverflowPool([]*types.Transaction{tx}) - pending, queue := pool.Stats() - - assert.Equal(t, 0, pending, "pending transactions mismatched") - assert.Equal(t, 0, queue, "queued transactions mismatched") - assert.Equal(t, uint64(1), pool.statsOverflowPool(), "OverflowPool size unexpected") - - tx2 := dynamicFeeTx(0, 100000, big.NewInt(3), big.NewInt(2), keys[1]) - pool.addToOverflowPool([]*types.Transaction{tx2}) - assert.Equal(t, uint64(1), pool.statsOverflowPool(), "OverflowPool size unexpected") - <-pool.requestPromoteExecutables(newAccountSet(pool.signer, from)) - time.Sleep(1 * time.Second) - pending, queue = pool.Stats() - - assert.Equal(t, 1, pending, "pending transactions mismatched") - assert.Equal(t, 0, queue, "queued transactions mismatched") - assert.Equal(t, uint64(0), pool.statsOverflowPool(), "OverflowPool size unexpected") - - tx3 := dynamicFeeTx(0, 100000, big.NewInt(3), big.NewInt(2), keys[2]) - pool.addToOverflowPool([]*types.Transaction{tx3}) - pending, queue = pool.Stats() - - assert.Equal(t, 1, pending, "pending transactions mismatched") - assert.Equal(t, 0, queue, "queued transactions mismatched") - assert.Equal(t, uint64(1), pool.statsOverflowPool(), "OverflowPool size unexpected") -} - // Tests that the pool rejects replacement dynamic fee transactions that don't // meet the minimum price bump required. func TestReplacementDynamicFee(t *testing.T) { diff --git a/core/txpool/legacypool/tx_overflowpool.go b/core/txpool/legacypool/tx_overflowpool.go deleted file mode 100644 index ee6a924e03..0000000000 --- a/core/txpool/legacypool/tx_overflowpool.go +++ /dev/null @@ -1,190 +0,0 @@ -package legacypool - -import ( - "container/heap" - "fmt" - "sync" - "time" - - "github.com/ethereum/go-ethereum/common" - "github.com/ethereum/go-ethereum/core/types" - "github.com/ethereum/go-ethereum/log" -) - -// txHeapItem implements the Interface interface (https://pkg.go.dev/container/heap#Interface) of heap so that it can be heapified -type txHeapItem struct { - tx *types.Transaction - timestamp int64 // Unix timestamp (nanoseconds) of when the transaction was added - index int -} - -type txHeap []*txHeapItem - -func (h txHeap) Len() int { return len(h) } -func (h txHeap) Less(i, j int) bool { - return h[i].timestamp < h[j].timestamp -} -func (h txHeap) Swap(i, j int) { - if i < 0 || j < 0 || i >= len(h) || j >= len(h) { - return // Silently fail if indices are out of bounds - } - h[i], h[j] = h[j], h[i] - if h[i] != nil { - h[i].index = i - } - if h[j] != nil { - h[j].index = j - } -} - -func (h *txHeap) Push(x interface{}) { - item, ok := x.(*txHeapItem) - if !ok { - return - } - n := len(*h) - item.index = n - *h = append(*h, item) -} - -func (h *txHeap) Pop() interface{} { - old := *h - n := len(old) - if n == 0 { - return nil // Return nil if the heap is empty - } - item := old[n-1] - old[n-1] = nil // avoid memory leak - *h = old[0 : n-1] - if item != nil { - item.index = -1 // for safety - } - return item -} - -type TxOverflowPool struct { - txHeap txHeap - index map[common.Hash]*txHeapItem - mu sync.RWMutex - maxSize uint64 // Maximum slots - totalSize uint64 // Total number of slots currently -} - -func NewTxOverflowPoolHeap(estimatedMaxSize uint64) *TxOverflowPool { - return &TxOverflowPool{ - txHeap: make(txHeap, 0, estimatedMaxSize), - index: make(map[common.Hash]*txHeapItem, estimatedMaxSize), - maxSize: estimatedMaxSize, - } -} - -func (tp *TxOverflowPool) Add(tx *types.Transaction) bool { - tp.mu.Lock() - defer tp.mu.Unlock() - - if _, exists := tp.index[tx.Hash()]; exists { - // Transaction already in pool, ignore - return false - } - - txSlots := uint64(numSlots(tx)) - - // If the transaction is too big to ever fit (and the pool isn't empty right now), reject it - if (txSlots > tp.maxSize) || (txSlots == tp.maxSize && tp.totalSize != 0) { - log.Debug("Transaction too large to fit in OverflowPool", "transaction", tx.Hash().String(), "requiredSlots", txSlots, "maxSlots", tp.maxSize) - return false - } - - // Remove transactions until there is room for the new transaction - for tp.totalSize+txSlots > tp.maxSize { - if tp.txHeap.Len() == 0 { - // No transactions left to remove, cannot make room - log.Warn("Not enough space in OverflowPool even after clearing", "transaction", tx.Hash().String()) - return false - } - // Remove the oldest transaction - oldestItem, ok := heap.Pop(&tp.txHeap).(*txHeapItem) - if !ok || oldestItem == nil { - log.Error("Failed to pop from txHeap during Add") - return false - } - delete(tp.index, oldestItem.tx.Hash()) - tp.totalSize -= uint64(numSlots(oldestItem.tx)) - OverflowPoolGauge.Dec(1) - } - - // Add the new transaction - item := &txHeapItem{ - tx: tx, - timestamp: time.Now().UnixNano(), - } - heap.Push(&tp.txHeap, item) - tp.index[tx.Hash()] = item - tp.totalSize += txSlots - OverflowPoolGauge.Inc(1) - - return true -} - -func (tp *TxOverflowPool) Get(hash common.Hash) (*types.Transaction, bool) { - tp.mu.RLock() - defer tp.mu.RUnlock() - if item, ok := tp.index[hash]; ok { - return item.tx, true - } - return nil, false -} - -func (tp *TxOverflowPool) Remove(hash common.Hash) { - tp.mu.Lock() - defer tp.mu.Unlock() - if item, ok := tp.index[hash]; ok { - heap.Remove(&tp.txHeap, item.index) - delete(tp.index, hash) - tp.totalSize -= uint64(numSlots(item.tx)) - OverflowPoolGauge.Dec(1) - } -} - -func (tp *TxOverflowPool) Flush(n int) []*types.Transaction { - tp.mu.Lock() - defer tp.mu.Unlock() - if n > tp.txHeap.Len() { - n = tp.txHeap.Len() - } - txs := make([]*types.Transaction, n) - for i := 0; i < n; i++ { - item, ok := heap.Pop(&tp.txHeap).(*txHeapItem) - if !ok || item == nil { - continue - } - txs[i] = item.tx - delete(tp.index, item.tx.Hash()) - tp.totalSize -= uint64(numSlots(item.tx)) - } - - OverflowPoolGauge.Dec(int64(n)) - return txs -} - -func (tp *TxOverflowPool) Len() int { - tp.mu.RLock() - defer tp.mu.RUnlock() - return tp.txHeap.Len() -} - -func (tp *TxOverflowPool) Size() uint64 { - tp.mu.RLock() - defer tp.mu.RUnlock() - return tp.totalSize -} - -func (tp *TxOverflowPool) PrintTxStats() { - tp.mu.RLock() - defer tp.mu.RUnlock() - for _, item := range tp.txHeap { - tx := item.tx - fmt.Printf("Hash: %s, Timestamp: %d, GasFeeCap: %s, GasTipCap: %s\n", - tx.Hash().String(), item.timestamp, tx.GasFeeCap().String(), tx.GasTipCap().String()) - } -} diff --git a/core/txpool/legacypool/tx_overflowpool_test.go b/core/txpool/legacypool/tx_overflowpool_test.go deleted file mode 100644 index ca8b6635f4..0000000000 --- a/core/txpool/legacypool/tx_overflowpool_test.go +++ /dev/null @@ -1,343 +0,0 @@ -package legacypool - -import ( - rand3 "crypto/rand" - "math/big" - rand2 "math/rand" - "testing" - "time" - - "github.com/cometbft/cometbft/libs/rand" - "github.com/ethereum/go-ethereum/common" - "github.com/ethereum/go-ethereum/core/types" - "github.com/stretchr/testify/assert" -) - -// Helper function to create a test transaction -func createTestTx(nonce uint64, gasPrice *big.Int) *types.Transaction { - to := common.HexToAddress("0x1234567890123456789012345678901234567890") - return types.NewTransaction(nonce, to, big.NewInt(1000), 21000, gasPrice, nil) -} - -func TestNewTxOverflowPoolHeap(t *testing.T) { - pool := NewTxOverflowPoolHeap(0) - if pool == nil { - t.Fatal("NewTxOverflowPoolHeap returned nil") - } - if pool.Len() != 0 { - t.Errorf("New pool should be empty, got length %d", pool.Len()) - } -} - -func TestTxOverflowPoolHeapAdd(t *testing.T) { - pool := NewTxOverflowPoolHeap(1) - tx := createTestTx(1, big.NewInt(1000)) - - pool.Add(tx) - if pool.Len() != 1 { - t.Errorf("Pool should have 1 transaction, got %d", pool.Len()) - } - - // Add the same transaction again - pool.Add(tx) - if pool.Len() != 1 { - t.Errorf("Pool should still have 1 transaction after adding duplicate, got %d", pool.Len()) - } -} - -func TestTxOverflowPoolHeapGet(t *testing.T) { - pool := NewTxOverflowPoolHeap(1) - tx := createTestTx(1, big.NewInt(1000)) - pool.Add(tx) - - gotTx, exists := pool.Get(tx.Hash()) - if !exists { - t.Fatal("Get returned false for existing transaction") - } - if gotTx.Hash() != tx.Hash() { - t.Errorf("Get returned wrong transaction. Want %v, got %v", tx.Hash(), gotTx.Hash()) - } - - _, exists = pool.Get(common.Hash{}) - if exists { - t.Error("Get returned true for non-existent transaction") - } -} - -func TestTxOverflowPoolHeapRemove(t *testing.T) { - pool := NewTxOverflowPoolHeap(1) - tx := createTestTx(1, big.NewInt(1000)) - pool.Add(tx) - - pool.Remove(tx.Hash()) - if pool.Len() != 0 { - t.Errorf("Pool should be empty after removing the only transaction, got length %d", pool.Len()) - } - - // Try to remove non-existent transaction - pool.Remove(common.Hash{}) - if pool.Len() != 0 { - t.Error("Removing non-existent transaction should not affect pool size") - } -} - -func TestTxOverflowPoolHeapPopN(t *testing.T) { - pool := NewTxOverflowPoolHeap(3) - tx1 := createTestTx(1, big.NewInt(1000)) - tx2 := createTestTx(2, big.NewInt(2000)) - tx3 := createTestTx(3, big.NewInt(3000)) - - pool.Add(tx1) - time.Sleep(time.Millisecond) // Ensure different timestamps - pool.Add(tx2) - time.Sleep(time.Millisecond) - pool.Add(tx3) - - popped := pool.Flush(2) - if len(popped) != 2 { - t.Fatalf("PopN(2) should return 2 transactions, got %d", len(popped)) - } - if popped[0].Hash() != tx1.Hash() || popped[1].Hash() != tx2.Hash() { - t.Error("PopN returned transactions in wrong order") - } - if pool.Len() != 1 { - t.Errorf("Pool should have 1 transaction left, got %d", pool.Len()) - } - - // Pop more than available - popped = pool.Flush(2) - if len(popped) != 1 { - t.Fatalf("PopN(2) should return 1 transaction when only 1 is left, got %d", len(popped)) - } - if popped[0].Hash() != tx3.Hash() { - t.Error("PopN returned wrong transaction") - } - if pool.Len() != 0 { - t.Errorf("Pool should be empty, got length %d", pool.Len()) - } -} - -func TestTxOverflowPoolHeapOrdering(t *testing.T) { - pool := NewTxOverflowPoolHeap(3) - tx1 := createTestTx(1, big.NewInt(1000)) - tx2 := createTestTx(2, big.NewInt(2000)) - tx3 := createTestTx(3, big.NewInt(3000)) - - pool.Add(tx2) - time.Sleep(time.Millisecond) // Ensure different timestamps - pool.Add(tx1) - pool.Add(tx3) // Added immediately after tx1, should have same timestamp but higher sequence - - popped := pool.Flush(3) - if len(popped) != 3 { - t.Fatalf("PopN(3) should return 3 transactions, got %d", len(popped)) - } - if popped[0].Hash() != tx2.Hash() || popped[1].Hash() != tx1.Hash() || popped[2].Hash() != tx3.Hash() { - t.Error("Transactions not popped in correct order (earliest timestamp first, then by sequence)") - } -} - -func TestTxOverflowPoolHeapLen(t *testing.T) { - pool := NewTxOverflowPoolHeap(2) - if pool.Len() != 0 { - t.Errorf("New pool should have length 0, got %d", pool.Len()) - } - - pool.Add(createTestTx(1, big.NewInt(1000))) - if pool.Len() != 1 { - t.Errorf("Pool should have length 1 after adding a transaction, got %d", pool.Len()) - } - - pool.Add(createTestTx(2, big.NewInt(2000))) - if pool.Len() != 2 { - t.Errorf("Pool should have length 2 after adding another transaction, got %d", pool.Len()) - } - - pool.Flush(1) - if pool.Len() != 1 { - t.Errorf("Pool should have length 1 after popping a transaction, got %d", pool.Len()) - } -} - -func TestTxOverflowPoolSlotCalculation(t *testing.T) { - // Initialize the pool with a maximum size of 2 - pool := NewTxOverflowPoolHeap(2) - - // Create two transactions with different slot requirements - tx1 := createTestTx(1, big.NewInt(1000)) // tx1 takes 1 slot - tx2 := createTestTx(2, big.NewInt(2000)) // tx2 takes 1 slot - - // Add both transactions to fill the pool - pool.Add(tx1) - pool.Add(tx2) - - if pool.Len() != 2 { - t.Fatalf("Expected pool size 2, but got %d", pool.Len()) - } - - dataSize := 40000 - tx3 := createLargeTestTx( - 3, // nonce - big.NewInt(100000000000), // gasPrice: 100 Gwei - dataSize, - ) // takes 2 slots - - // Create a third transaction with more slots than tx1 - tx3Added := pool.Add(tx3) - assert.Equal(t, false, tx3Added) - assert.Equal(t, uint64(2), pool.totalSize) - - // Verify that the pool length remains at 2 - assert.Equal(t, 2, pool.Len(), "Expected pool size 2 after overflow") - - tx4 := createTestTx(4, big.NewInt(3000)) // tx4 takes 1 slot - // Add tx4 to the pool - assert.True(t, pool.Add(tx4), "Failed to add tx4") - - // The pool should evict the oldest transaction (tx1) to make room for tx4 - // Verify that tx1 is no longer in the pool - _, exists := pool.Get(tx1.Hash()) - assert.False(t, exists, "Expected tx1 to be evicted from the pool") -} - -func TestBiggerTx(t *testing.T) { - // Create a transaction with 40KB of data (which should take 2 slots) - dataSize := 40000 - tx := createLargeTestTx( - 0, // nonce - big.NewInt(100000000000), // gasPrice: 100 Gwei - dataSize, - ) - numberOfSlots := numSlots(tx) - assert.Equal(t, 2, numberOfSlots) -} - -// Helper function to create a random test transaction -func createRandomTestTx() *types.Transaction { - nonce := uint64(rand.Intn(1000000)) - to := common.BytesToAddress(rand.Bytes(20)) - amount := new(big.Int).Rand(rand2.New(rand2.NewSource(rand.Int63())), big.NewInt(1e18)) - gasLimit := uint64(21000) - gasPrice := new(big.Int).Rand(rand2.New(rand2.NewSource(rand.Int63())), big.NewInt(1e9)) - data := rand.Bytes(100) - return types.NewTransaction(nonce, to, amount, gasLimit, gasPrice, data) -} - -func createRandomTestTxs(n int) []*types.Transaction { - txs := make([]*types.Transaction, n) - for i := 0; i < n; i++ { - txs[i] = createRandomTestTx() - } - return txs -} - -// createLargeTestTx creates a transaction with a large data payload -func createLargeTestTx(nonce uint64, gasPrice *big.Int, dataSize int) *types.Transaction { - // Generate random data of specified size - data := make([]byte, dataSize) - rand3.Read(data) - - to := common.HexToAddress("0x1234567890123456789012345678901234567890") - - // Calculate gas needed for the data - // Gas costs: 21000 (base) + 16 (per non-zero byte) or 4 (per zero byte) - gasLimit := uint64(21000 + (16 * len(data))) - - return types.NewTransaction( - nonce, - to, - big.NewInt(1000), - gasLimit, - gasPrice, - data, - ) -} - -// goos: darwin -// goarch: arm64 -// pkg: github.com/ethereum/go-ethereum/core/txpool/legacypool -// BenchmarkTxOverflowPoolHeapAdd-8 813326 2858 ns/op -func BenchmarkTxOverflowPoolHeapAdd(b *testing.B) { - pool := NewTxOverflowPoolHeap(uint64(b.N)) - txs := createRandomTestTxs(b.N) - b.ResetTimer() - for i := 0; i < b.N; i++ { - pool.Add(txs[i]) - } -} - -// BenchmarkTxOverflowPoolHeapGet-8 32613938 35.63 ns/op -func BenchmarkTxOverflowPoolHeapGet(b *testing.B) { - pool := NewTxOverflowPoolHeap(1000) - txs := createRandomTestTxs(1000) - for _, tx := range txs { - pool.Add(tx) - } - b.ResetTimer() - for i := 0; i < b.N; i++ { - pool.Get(txs[i%1000].Hash()) - } -} - -// BenchmarkTxOverflowPoolHeapRemove-8 3020841 417.8 ns/op -func BenchmarkTxOverflowPoolHeapRemove(b *testing.B) { - pool := NewTxOverflowPoolHeap(uint64(b.N)) - txs := createRandomTestTxs(b.N) - for _, tx := range txs { - pool.Add(tx) - } - b.ResetTimer() - for i := 0; i < b.N; i++ { - pool.Remove(txs[i].Hash()) - } -} - -// BenchmarkTxOverflowPoolHeapFlush-8 42963656 29.90 ns/op -func BenchmarkTxOverflowPoolHeapFlush(b *testing.B) { - pool := NewTxOverflowPoolHeap(1000) - txs := createRandomTestTxs(1000) - for _, tx := range txs { - pool.Add(tx) - } - b.ResetTimer() - for i := 0; i < b.N; i++ { - pool.Flush(10) - } -} - -// BenchmarkTxOverflowPoolHeapLen-8 79147188 20.07 ns/op -func BenchmarkTxOverflowPoolHeapLen(b *testing.B) { - pool := NewTxOverflowPoolHeap(1000) - txs := createRandomTestTxs(1000) - for _, tx := range txs { - pool.Add(tx) - } - b.ResetTimer() - for i := 0; i < b.N; i++ { - pool.Len() - } -} - -// BenchmarkTxOverflowPoolHeapAddRemove-8 902896 1546 ns/op -func BenchmarkTxOverflowPoolHeapAddRemove(b *testing.B) { - pool := NewTxOverflowPoolHeap(uint64(b.N)) - txs := createRandomTestTxs(b.N) - b.ResetTimer() - for i := 0; i < b.N; i++ { - pool.Add(txs[i]) - pool.Remove(txs[i].Hash()) - } -} - -// BenchmarkTxOverflowPoolHeapAddFlush-8 84417 14899 ns/op -func BenchmarkTxOverflowPoolHeapAddFlush(b *testing.B) { - pool := NewTxOverflowPoolHeap(uint64(b.N * 10)) - txs := createRandomTestTxs(b.N * 10) - b.ResetTimer() - for i := 0; i < b.N; i++ { - for j := 0; j < 10; j++ { - pool.Add(txs[i*10+j]) - } - pool.Flush(10) - } -} diff --git a/core/txpool/subpool.go b/core/txpool/subpool.go index 344a52034f..e60f01506f 100644 --- a/core/txpool/subpool.go +++ b/core/txpool/subpool.go @@ -182,9 +182,6 @@ type SubPool interface { // identified by their hashes. Status(hash common.Hash) TxStatus - // SetMaxGas limit max acceptable tx gas when mine is enabled - SetMaxGas(maxGas uint64) - // Clear removes all tracked transactions from the pool Clear() } diff --git a/core/txpool/txpool.go b/core/txpool/txpool.go index 681f00af29..4931413875 100644 --- a/core/txpool/txpool.go +++ b/core/txpool/txpool.go @@ -263,12 +263,6 @@ func (p *TxPool) SetGasTip(tip *big.Int) { } } -func (p *TxPool) SetMaxGas(gas uint64) { - for _, subpool := range p.subpools { - subpool.SetMaxGas(gas) - } -} - // Has returns an indicator whether the pool has a transaction cached with the // given hash. func (p *TxPool) Has(hash common.Hash) bool { diff --git a/core/txpool/validation.go b/core/txpool/validation.go index 76338e04ec..1c9e19b94b 100644 --- a/core/txpool/validation.go +++ b/core/txpool/validation.go @@ -25,6 +25,7 @@ import ( "github.com/ethereum/go-ethereum/core" "github.com/ethereum/go-ethereum/core/state" "github.com/ethereum/go-ethereum/core/types" + "github.com/ethereum/go-ethereum/core/vm" "github.com/ethereum/go-ethereum/crypto/kzg4844" "github.com/ethereum/go-ethereum/log" "github.com/ethereum/go-ethereum/params" @@ -45,7 +46,6 @@ type ValidationOptions struct { MaxSize uint64 // Maximum size of a transaction that the caller can meaningfully handle MinTip *big.Int // Minimum gas tip needed to allow a transaction into the caller pool MaxBlobCount int // Maximum number of blobs allowed per transaction - MaxGas uint64 // Max acceptable transaction gas in the txpool } // ValidationFunction is an method type which the pools use to perform the tx-validations which do not @@ -88,7 +88,7 @@ func ValidateTransaction(tx *types.Transaction, head *types.Header, signer types } // Check whether the init code size has been exceeded if rules.IsShanghai && tx.To() == nil && len(tx.Data()) > params.MaxInitCodeSize { - return fmt.Errorf("%w: code size %v, limit %v", core.ErrMaxInitCodeSizeExceeded, len(tx.Data()), params.MaxInitCodeSize) + return fmt.Errorf("%w: code size %v, limit %v", vm.ErrMaxInitCodeSizeExceeded, len(tx.Data()), params.MaxInitCodeSize) } if rules.IsOsaka && tx.Gas() > params.MaxTxGas { return fmt.Errorf("%w (cap: %d, tx: %d)", core.ErrGasLimitTooHigh, params.MaxTxGas, tx.Gas()) @@ -103,11 +103,6 @@ func ValidateTransaction(tx *types.Transaction, head *types.Header, signer types return ErrGasLimit } - // Ensure the transaction doesn't exceed the current miner max acceptable limit gas - if opts.MaxGas > 0 && tx.Gas() > opts.MaxGas { - return fmt.Errorf("%w (cap: %d, tx: %d)", core.ErrGasLimitTooHigh, opts.MaxGas, tx.Gas()) - } - // Sanity check for extremely large numbers (supported by RLP or RPC) if tx.GasFeeCap().BitLen() > 256 { return core.ErrFeeCapVeryHigh diff --git a/core/types.go b/core/types.go index e27395f5c3..2e27fcd5d5 100644 --- a/core/types.go +++ b/core/types.go @@ -49,8 +49,6 @@ type Prefetcher interface { Prefetch(transactions types.Transactions, header *types.Header, gasLimit uint64, statedb *state.StateDB, cfg vm.Config, interrupt *atomic.Bool) // PrefetchMining used for pre-caching transaction signatures and state trie nodes. Only used for mining stage. PrefetchMining(txs TransactionsByPriceAndNonce, header *types.Header, gasLimit uint64, statedb *state.StateDB, cfg vm.Config, interruptCh <-chan struct{}, txCurr **types.Transaction) - // prefetch based on block access list - PrefetchBAL(block *types.Block, statedb *state.StateDB, interruptChan <-chan struct{}) } // Processor is an interface for processing blocks using a given initial state. diff --git a/core/types/block.go b/core/types/block.go index 6b81e63a97..7dc9f4f30e 100644 --- a/core/types/block.go +++ b/core/types/block.go @@ -235,123 +235,6 @@ type Body struct { Withdrawals []*Withdrawal `rlp:"optional"` } -// StorageAccessItem is a single storage key that is accessed in a block. -type StorageAccessItem struct { - TxIndex uint32 // index of the first transaction in the block that accessed the storage - Dirty bool // true if the storage was modified in the block, false if it was read only - Key common.Hash -} - -// AccountAccessListEncode & BlockAccessListEncode are for BAL serialization. -type AccountAccessListEncode struct { - TxIndex uint32 // index of the first transaction in the block that accessed the account - Address common.Address - StorageItems []StorageAccessItem -} - -type BlockAccessListEncode struct { - Version uint32 // Version of the access list format - Number uint64 // number of the block that the BAL is for - Hash common.Hash // hash of the block that the BAL is for - SignData []byte // sign data for BAL - Accounts []AccountAccessListEncode -} - -// TxAccessListPrefetch & BlockAccessListPrefetch are for BAL prefetch -type StorageAccessItemPrefetch struct { - Dirty bool - Key common.Hash -} - -type TxAccessListPrefetch struct { - Accounts map[common.Address][]StorageAccessItemPrefetch -} - -type BlockAccessListPrefetch struct { - AccessListItems map[uint32]TxAccessListPrefetch -} - -func (b *BlockAccessListPrefetch) Update(aclEncode *AccountAccessListEncode) { - if aclEncode == nil { - return - } - accAddr := aclEncode.Address - b.PrepareTxAccount(aclEncode.TxIndex, accAddr) - for _, storageItem := range aclEncode.StorageItems { - b.PrepareTxStorage(accAddr, storageItem) - } -} - -func (b *BlockAccessListPrefetch) PrepareTxStorage(accAddr common.Address, storageItem StorageAccessItem) { - b.PrepareTxAccount(storageItem.TxIndex, accAddr) - txAccessList := b.AccessListItems[storageItem.TxIndex] - txAccessList.Accounts[accAddr] = append(txAccessList.Accounts[accAddr], StorageAccessItemPrefetch{ - Dirty: storageItem.Dirty, - Key: storageItem.Key, - }) -} -func (b *BlockAccessListPrefetch) PrepareTxAccount(txIndex uint32, addr common.Address) { - // create the tx access list if not exists - if _, ok := b.AccessListItems[txIndex]; !ok { - b.AccessListItems[txIndex] = TxAccessListPrefetch{ - Accounts: make(map[common.Address][]StorageAccessItemPrefetch), - } - } - // create the account access list if not exists - if _, ok := b.AccessListItems[txIndex].Accounts[addr]; !ok { - b.AccessListItems[txIndex].Accounts[addr] = make([]StorageAccessItemPrefetch, 0) - } -} - -// BlockAccessListRecord & BlockAccessListRecord are used to record access list during tx execution. -type AccountAccessListRecord struct { - TxIndex uint32 // index of the first transaction in the block that accessed the account - StorageItems map[common.Hash]StorageAccessItem -} - -type BlockAccessListRecord struct { - Version uint32 // Version of the access list format - Accounts map[common.Address]AccountAccessListRecord -} - -func (b *BlockAccessListRecord) AddAccount(addr common.Address, txIndex uint32) { - if b == nil { - return - } - - if _, ok := b.Accounts[addr]; !ok { - b.Accounts[addr] = AccountAccessListRecord{ - TxIndex: txIndex, - StorageItems: make(map[common.Hash]StorageAccessItem), - } - } -} - -func (b *BlockAccessListRecord) AddStorage(addr common.Address, key common.Hash, txIndex uint32, dirty bool) { - if b == nil { - return - } - - if _, ok := b.Accounts[addr]; !ok { - b.Accounts[addr] = AccountAccessListRecord{ - TxIndex: txIndex, - StorageItems: make(map[common.Hash]StorageAccessItem), - } - } - - if _, ok := b.Accounts[addr].StorageItems[key]; !ok { - b.Accounts[addr].StorageItems[key] = StorageAccessItem{ - TxIndex: txIndex, - Dirty: dirty, - Key: key, - } - } else { - storageItem := b.Accounts[addr].StorageItems[key] - storageItem.Dirty = dirty - b.Accounts[addr].StorageItems[key] = storageItem - } -} - // Block represents an Ethereum block. // // Note the Block type tries to be 'immutable', and contains certain caches that rely @@ -391,10 +274,6 @@ type Block struct { // sidecars provides DA check sidecars BlobSidecars - - // bal provides block access list - bal *BlockAccessListEncode - balSize atomic.Uint64 } // "external" block encoding. used for eth protocol, etc. @@ -617,19 +496,6 @@ func (b *Block) Size() uint64 { return uint64(c) } -func (b *Block) BALSize() uint64 { - if b.bal == nil { - return 0 - } - if size := b.balSize.Load(); size > 0 { - return size - } - c := writeCounter(0) - rlp.Encode(&c, b.bal) - b.balSize.Store(uint64(c)) - return uint64(c) -} - func (b *Block) SetRoot(root common.Hash) { b.header.Root = root } // SanityCheck can be used to prevent that unbounded fields are @@ -642,10 +508,6 @@ func (b *Block) Sidecars() BlobSidecars { return b.sidecars } -func (b *Block) BAL() *BlockAccessListEncode { - return b.bal -} - func (b *Block) CleanSidecars() { b.sidecars = make(BlobSidecars, 0) } @@ -701,7 +563,6 @@ func (b *Block) WithSeal(header *Header) *Block { withdrawals: b.withdrawals, witness: b.witness, sidecars: b.sidecars, - bal: b.bal, } } @@ -715,7 +576,6 @@ func (b *Block) WithBody(body Body) *Block { withdrawals: slices.Clone(body.Withdrawals), witness: b.witness, sidecars: b.sidecars, - bal: b.bal, } for i := range body.Uncles { block.uncles[i] = CopyHeader(body.Uncles[i]) @@ -731,7 +591,6 @@ func (b *Block) WithWithdrawals(withdrawals []*Withdrawal) *Block { uncles: b.uncles, witness: b.witness, sidecars: b.sidecars, - bal: b.bal, } if withdrawals != nil { block.withdrawals = make([]*Withdrawal, len(withdrawals)) @@ -748,7 +607,6 @@ func (b *Block) WithSidecars(sidecars BlobSidecars) *Block { uncles: b.uncles, withdrawals: b.withdrawals, witness: b.witness, - bal: b.bal, } if sidecars != nil { block.sidecars = make(BlobSidecars, len(sidecars)) @@ -757,23 +615,6 @@ func (b *Block) WithSidecars(sidecars BlobSidecars) *Block { return block } -func (b *Block) WithBAL(bal *BlockAccessListEncode) *Block { - block := &Block{ - header: b.header, - transactions: b.transactions, - uncles: b.uncles, - withdrawals: b.withdrawals, - witness: b.witness, - sidecars: b.sidecars, - } - block.bal = bal - return block -} - -func (b *Block) UpdateBAL(bal *BlockAccessListEncode) { - b.bal = bal -} - func (b *Block) WithWitness(witness *ExecutionWitness) *Block { return &Block{ header: b.header, diff --git a/core/types/builder/bep-675-builder-integration.md b/core/types/builder/bep-675-builder-integration.md new file mode 100644 index 0000000000..4b292d0f21 --- /dev/null +++ b/core/types/builder/bep-675-builder-integration.md @@ -0,0 +1,185 @@ +This document describes the concrete builder-side integration details for the BidBlock path: API call chain, payload assembly, signature, permission lifecycle, error handling, and timing. + +For the protocol design and high-level workflow, see [BEP-675: Builder-Proposed Block with Validator Blind Signing](https://github.com/bnb-chain/BEPs/blob/master/BEPs/BEP-675.md). This document does not restate the rationale covered there. + +## Workflow + +The builder's end-to-end flow for producing and submitting a BidBlock: + +``` +parent header / state + → initialize header skeleton + → Parlia.PrepareForBidBlock + fills Coinbase / Difficulty / Time / MixDigest / Extra / Nonce + (Extra will be overwritten by the validator) + + → select and execute user txs + produces body.Transactions / receipts / updated state + + → Parlia.FinalizeAndAssembleBidBlock + executes and appends unsigned system tx + returns the complete block + + → block → builder.BidBlock + Header = block.Header() + Transactions = tx.MarshalBinary() + Sidecars = block.Sidecars() + + → Sign BidBlock.Hash() + produces builder.BidBlockArgs + + → mev_getBidBlockPermission(builder) + (cached; if !allowed, fall back to mev_sendBid) + + → mev_sendBidBlock +``` + +## 1. Prepare the Header Skeleton + +The builder first fills in the locally known fields, then calls `PrepareForBidBlock` to complete the Parlia consensus fields: + +```go +header := &types.Header{ + ParentHash: parent.Hash(), + Number: new(big.Int).Add(parent.Number, common.Big1), + GasLimit: gasLimit, + BaseFee: baseFee, +} +err := parliaEngine.PrepareForBidBlock(chain, header) +``` + +`PrepareForBidBlock` writes `Coinbase` / `Difficulty` / `Time` / `MixDigest` / `Extra` / `Nonce`. `Coinbase` is taken from the parent snapshot's `inturnValidator()`, not the local `p.val` — the builder does not have a validator key. + +## 2. Execute User Transactions + +Transaction selection and EVM execution are entirely builder-driven; this specification does not constrain them. The builder runs selected user transactions against the parent state and maintains `state` / `receipts` / `body.Transactions` / `sidecars`. + +## 3. Finalize (generate unsigned system tx) + +```go +block, receipts, err := parliaEngine.FinalizeAndAssembleBidBlock( + chain, header, state, body, receipts, tracer, +) +``` + +**Input:** + +- The `header` / `state` / `body` / `receipts` after user txs have already been executed. + +**Execution:** + +1. Enters `finalizeAndAssemble(..., systemTxPacking)`. +2. Generates and executes the trailing system txs per Parlia rules: + - `deposit` (always) + - `distributeFinalityReward` (every 200 blocks) + - `updateValidatorSetV2` (breathe blocks only) +3. The system tx genuinely executes on the EVM: + - updates state + - increases `header.GasUsed` + - appends a receipt + - affects `Root` / `ReceiptHash` / `Bloom` / `GasUsed` +4. However, in `systemTxPacking` mode the transactions are **not** signed with the validator key: + - the system txs appended to the block are unsigned (v/r/s = 0, gasPrice = 0) +5. Computes the final state root and assembles the block from `header` + `body` + `receipts`. + +**Output:** + +- the complete block (with unsigned trailing system txs) +- the complete receipts + +Signing does not affect EVM state transitions, so the execution results are identical whether the system transactions are signed (validator-mining path) or unsigned (builder packing path). The validator bind-signs these unsigned system txs at seal time and recomputes `TxHash`. + +`GasFee` is not a wire field of `BidBlock`. The validator derives it from the `value` of the trailing `deposit` system transaction and uses it to rank competing BidBlocks for the same parent. + +## 4. Assemble the BidBlock Payload + +```go +txBytes := make([]hexutil.Bytes, len(block.Transactions())) +for i, tx := range block.Transactions() { + enc, _ := tx.MarshalBinary() + txBytes[i] = enc +} +bidBlock := &builder.BidBlock{ + Header: block.Header(), + Transactions: txBytes, + Sidecars: block.Sidecars(), +} +``` + +**Hard ordering constraint:** user txs come first, unsigned system txs come last. + +## 5. Signing + +```go +sig, _ := crypto.Sign(bidBlock.Hash().Bytes(), builderKey) +args := &builder.BidBlockArgs{BidBlock: bidBlock, Signature: sig} +``` + +A bare keccak digest, with no EIP-191/712 prefix, consistent with the existing `mev_sendBid`. The validator recovers the address using `args.EcrecoverSender()`. + +## 6. Send and Fallback + +### Check permission + +Builders poll `mev_getBidBlockPermission` to determine whether the BidBlock path is currently open for them on a given validator, and fall back to legacy `mev_sendBid` when it is not. + +The RPC does not surface permission denial through a JSON-RPC error; state is carried in the `allowed` field of the result. When `allowed` is false, `reason` identifies why. Current values: + +- `insertchain_failed` — the last sealed BidBlock from this builder failed validator-side `InsertChain` (e.g. invalid state root, mismatched receipt hash, KZG proof failure). +- `gasprice_too_low` — the sealed BidBlock imported successfully, but its average gas price (excluding system transactions) was below the validator's configured minimum. +- `manual` — admin revoke via `admin_setBidBlockPermission`. + +`mev_getBidBlockPermission` response: + +```jsonc +{ + "allowed": false, + "reason": "insertchain_failed", + "blockHash": "0x...", + "blockNumber": "0x123", + "revokedAt": "2026-05-22T...", // when the revoke happened + "resetAt": "2026-05-23T00:00:00Z" // when the revoke expires (RPC returns the lockout expiry; builder may treat as informational) +} +``` + +### `mev_sendBidBlock` error mapping + +The main BidBlock failure modes have dedicated JSON-RPC codes; match by code where possible. Code `-38001` remains a catch-all for parameter / pre-check errors, so still inspect the message for those. + +| Error message contains | JSON-RPC code | Builder action | +| --- | --- | --- | +| `BidBlock disabled, fallback to SendBid` | -38001 | fallback to `mev_sendBid` | +| `builder BidBlock permission revoked, fallback to SendBid` | -38006 | permission not allowed; fallback to `mev_sendBid` | +| `pre-seal verify failed: ...` | -38007 | **fix build logic; do NOT retry the same BidBlock** | +| `too late, expected before ...` | -38008 | dropped; next slot | +| `the validator stop accepting bids ...` | -38003 | validator paused; retry later | +| `the validator is working on too many bids ...` | -38004 | validator busy/overloaded (admission timed out); retry later | +| `the validator is not in-turn ...` | -38005 | next slot or try another validator | +| `too many bids: exceeded limit of N bids per builder per block` | _(no dedicated code; plain JSON-RPC error)_ | per-builder quota hit (`mev_params.MaxBidsPerBuilder`); retry next slot or fall back to `mev_sendBid` | + +**Recommended practice:** + +- Poll `mev_getBidBlockPermission` once every 5–10 seconds and cache the current validator's BidBlock permission for that builder. +- For each validator, periodically query `mev_params` to check whether that validator has BidBlock enabled (`BidBlockEnabled` field). When disabled, treat it the same as permission denied and fall back to legacy `mev_sendBid`. + +### BidBlock send window + +The BidBlock path skips validator-side simulation, so the receive deadline is: + +``` +BidMustBefore = parent.MilliTimestamp + BlockInterval - DelayLeftOver // 15ms +``` + +As the validator still needs µs-level time for signature recovery, tx decoding, pre-seal verification, and `Extra` overwrite before sealing, arrivals **exactly at** `BidMustBefore` may still miss the seal. We recommend builders leave a buffer of ≈100µs–1ms before `BidMustBefore`. + +The transmission latency on the wire is not constant: the number of transactions and the number of blobs in the BidBlock both increase the payload size and therefore the time it takes to reach the validator. A larger BidBlock arrives later, so this transmission cost must be factored into the send-window control logic (e.g. estimate the on-wire delay from the current tx/blob count and bring the send time forward accordingly), rather than assuming a fixed offset before `BidMustBefore`. + +## Summary + +1. GasFee does not need to be provided explicitly; the validator derives it from the trailing deposit system tx. +2. The validator overwrites `Extra` and recomputes `TxHash` after bind-signing the system tx; all other header fields are used as-is from the builder. +3. The BidBlock send window is later than legacy `mev_sendBid` because no validator-side simulation is needed (see [BidBlock send window](#bidblock-send-window)). +4. BidBlock and the legacy bid share the same per-block quota, exposed via `mev_params.MaxBidsPerBuilder`. +5. Permission must be polled continuously (every 5–10 seconds is recommended); the cache is also invalidated whenever `mev_sendBidBlock` returns "permission revoked". When `mev_params.BidBlockEnabled == false`, treat it the same as permission denied. +6. The builder must handle BidBlock failure paths: (1) `mev_sendBidBlock` may return a direct error; (2) permission may be revoked, with the reason exposed by `mev_getBidBlockPermission`; (3) validator admin or local policy changes may later restore or revoke permission. +7. **Send the BidBlock as close to `BidMustBefore` as possible** (leaving the ≈100µs buffer noted above) — a later send leaves more time for transaction selection and execution, maximizing the value packed into the block. diff --git a/core/types/bid.go b/core/types/builder/bid.go similarity index 51% rename from core/types/bid.go rename to core/types/builder/bid.go index 4f7d52f7d5..32f932bf6e 100644 --- a/core/types/bid.go +++ b/core/types/builder/bid.go @@ -1,4 +1,4 @@ -package types +package builder import ( "fmt" @@ -10,7 +10,10 @@ import ( "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/common/hexutil" + "github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/crypto" + "github.com/ethereum/go-ethereum/log" + "github.com/ethereum/go-ethereum/rlp" ) const TxDecodeConcurrencyForPerBid = 5 @@ -36,7 +39,7 @@ func (b *BidArgs) EcrecoverSender() (common.Address, error) { return crypto.PubkeyToAddress(*pk), nil } -func (b *BidArgs) ToBid(builder common.Address, signer Signer) (*Bid, error) { +func (b *BidArgs) ToBid(builder common.Address, signer types.Signer) (*Bid, error) { txs, err := b.RawBid.DecodeTxs(signer) if err != nil { return nil, err @@ -49,7 +52,7 @@ func (b *BidArgs) ToBid(builder common.Address, signer Signer) (*Bid, error) { unRevertibleHashes.Append(b.RawBid.UnRevertible...) if len(b.PayBidTx) != 0 { - var payBidTx = new(Transaction) + var payBidTx = new(types.Transaction) err = payBidTx.UnmarshalBinary(b.PayBidTx) if err != nil { return nil, err @@ -90,21 +93,21 @@ type RawBid struct { hash atomic.Value } -func (b *RawBid) DecodeTxs(signer Signer) ([]*Transaction, error) { +func (b *RawBid) DecodeTxs(signer types.Signer) ([]*types.Transaction, error) { if len(b.Txs) == 0 { - return []*Transaction{}, nil + return []*types.Transaction{}, nil } txChan := make(chan int, len(b.Txs)) - bidTxs := make([]*Transaction, len(b.Txs)) - decode := func(txBytes hexutil.Bytes) (*Transaction, error) { - tx := new(Transaction) + bidTxs := make([]*types.Transaction, len(b.Txs)) + decode := func(txBytes hexutil.Bytes) (*types.Transaction, error) { + tx := new(types.Transaction) err := tx.UnmarshalBinary(txBytes) if err != nil { return nil, err } - _, err = Sender(signer, tx) + _, err = types.Sender(signer, tx) if err != nil { return nil, err } @@ -167,7 +170,7 @@ type Bid struct { Builder common.Address BlockNumber uint64 ParentHash common.Hash - Txs Transactions + Txs types.Transactions UnRevertible mapset.Set[common.Hash] GasUsed uint64 GasFee *big.Int @@ -202,6 +205,106 @@ type BidIssue struct { Message string } +// BidBlockArgs is the input for the SendBidBlock RPC. +type BidBlockArgs struct { + BidBlock *BidBlock + Signature hexutil.Bytes `json:"signature"` +} + +// EcrecoverSender recovers the builder address from the signature over BidBlock.Hash(). +func (b *BidBlockArgs) EcrecoverSender() (common.Address, error) { + pk, err := crypto.SigToPub(b.BidBlock.Hash().Bytes(), b.Signature) + if err != nil { + return common.Address{}, err + } + return crypto.PubkeyToAddress(*pk), nil +} + +// ToDecodedBidBlock converts BidBlockArgs to a decoded internal representation. +// Note: transaction sender recovery is deferred to InsertChain. +func (b *BidBlockArgs) ToDecodedBidBlock(builder common.Address) (*DecodedBidBlock, error) { + txs, err := b.DecodeTxs() + if err != nil { + return nil, err + } + + sidecars := b.BidBlock.Sidecars + if sidecars == nil { + sidecars = types.BlobSidecars{} + } + + return &DecodedBidBlock{ + Builder: builder, + Header: types.CopyHeader(b.BidBlock.Header), + Txs: txs, + Sidecars: sidecars, + bidHash: b.BidBlock.Hash(), + }, nil +} + +// DecodeTxs decodes user txs followed by unsigned system txs. +func (b *BidBlockArgs) DecodeTxs() ([]*types.Transaction, error) { + txs := make([]*types.Transaction, len(b.BidBlock.Transactions)) + for i, txBytes := range b.BidBlock.Transactions { + tx := new(types.Transaction) + if err := tx.UnmarshalBinary(txBytes); err != nil { + return nil, fmt.Errorf("failed to decode tx %d: %v", i, err) + } + txs[i] = tx + } + return txs, nil +} + +// BidBlock is the builder-proposed block carried by BidBlockArgs. +type BidBlock struct { + Header *types.Header `json:"header"` + Transactions []hexutil.Bytes `json:"transactions"` // user txs first, unsigned system txs last + Sidecars types.BlobSidecars `json:"sidecars,omitempty"` + + hash atomic.Value +} + +// Hash returns the BidBlock signing hash. The header carries TxHash, and the +// validator checks TxHash against Transactions before blind-signing. +func (b *BidBlock) Hash() common.Hash { + if hash := b.hash.Load(); hash != nil { + return hash.(common.Hash) + } + start := time.Now() + h := b.Header.Hash() + log.Debug("BidBlock Hash() computed", "number", b.Header.Number, "elapsed", time.Since(start), + "txs", len(b.Transactions), "sidecars", len(b.Sidecars)) + b.hash.Store(h) + return h +} + +// DecodedBidBlock is the validator-side decoded representation of a BidBlock. +type DecodedBidBlock struct { + Builder common.Address // recovered from BidBlockArgs.Signature + Header *types.Header + Txs types.Transactions + Sidecars types.BlobSidecars + GasFee *big.Int + SystemTxStart int // index in Txs where the unsigned trailing system-tx region begins; set during admission. + + bidHash common.Hash +} + +// Hash returns the hash of the original BidBlock payload. +func (d *DecodedBidBlock) Hash() common.Hash { + return d.bidHash +} + +// BlockNumber returns the block number from the header. +func (d *DecodedBidBlock) BlockNumber() uint64 { + return d.Header.Number.Uint64() +} + +// ParentHash returns the parent hash from the header. +func (d *DecodedBidBlock) ParentHash() common.Hash { + return d.Header.ParentHash +} + type MevParams struct { ValidatorCommission uint64 // 100 means 1% BidSimulationLeftOver time.Duration @@ -210,5 +313,16 @@ type MevParams struct { GasCeil uint64 GasPrice *big.Int // Minimum avg gas price for bid block BuilderFeeCeil *big.Int + BidBlockEnabled bool // whether mev_sendBidBlock is accepted Version string } + +// rlpHash encodes x and returns the keccak256 hash of the encoding. It mirrors +// the unexported helper in package types, replicated here so the bid/bidblock +// hashing stays byte-for-byte identical after moving out of core/types. +func rlpHash(x interface{}) (h common.Hash) { + sha := crypto.NewKeccakState() + rlp.Encode(sha, x) + sha.Read(h[:]) + return h +} diff --git a/core/types/builder/bid_block_permission.go b/core/types/builder/bid_block_permission.go new file mode 100644 index 0000000000..2d7aee19cd --- /dev/null +++ b/core/types/builder/bid_block_permission.go @@ -0,0 +1,16 @@ +package builder + +import ( + "time" + + "github.com/ethereum/go-ethereum/common" +) + +type BidBlockPermissionStatus struct { + Allowed bool + Reason string // err detail for auto revokes (InsertChain failure), or "manual" for admin revokes + BlockHash common.Hash + BlockNum uint64 + RevokedAt time.Time + ResetAt time.Time +} diff --git a/core/types/bid_error.go b/core/types/builder/bid_error.go similarity index 59% rename from core/types/bid_error.go rename to core/types/builder/bid_error.go index 6b543ae64f..ac9008ab23 100644 --- a/core/types/bid_error.go +++ b/core/types/builder/bid_error.go @@ -1,13 +1,16 @@ -package types +package builder import "errors" const ( - InvalidBidParamError = -38001 - InvalidPayBidTxError = -38002 - MevNotRunningError = -38003 - MevBusyError = -38004 - MevNotInTurnError = -38005 + InvalidBidParamError = -38001 + InvalidPayBidTxError = -38002 + MevNotRunningError = -38003 + MevBusyError = -38004 + MevNotInTurnError = -38005 + BidBlockPermissionRevokedError = -38006 + BidBlockPreSealVerifyError = -38007 + BidBlockTooLateError = -38008 ) var ( @@ -37,6 +40,18 @@ func NewInvalidPayBidTxError(message string) *bidError { return newBidError(errors.New(message), InvalidPayBidTxError) } +func NewBidBlockPermissionRevokedError(message string) *bidError { + return newBidError(errors.New(message), BidBlockPermissionRevokedError) +} + +func NewBidBlockPreSealVerifyError(message string) *bidError { + return newBidError(errors.New(message), BidBlockPreSealVerifyError) +} + +func NewBidBlockTooLateError(message string) *bidError { + return newBidError(errors.New(message), BidBlockTooLateError) +} + func newBidError(err error, code int) *bidError { return &bidError{ error: err, diff --git a/core/types/builder/bid_test.go b/core/types/builder/bid_test.go new file mode 100644 index 0000000000..adfe8d0c21 --- /dev/null +++ b/core/types/builder/bid_test.go @@ -0,0 +1,65 @@ +// Copyright 2026 The go-ethereum Authors +// This file is part of the go-ethereum library. + +package builder + +import ( + "math/big" + "testing" + + "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/core/types" +) + +func TestBidBlockArgsToDecodedBidBlockNormalizesNilSidecars(t *testing.T) { + args := &BidBlockArgs{ + BidBlock: &BidBlock{ + Header: &types.Header{ + Difficulty: big.NewInt(1), + Number: big.NewInt(1), + Extra: make([]byte, 32), + }, + }, + } + + decoded, err := args.ToDecodedBidBlock(common.Address{0x1}) + if err != nil { + t.Fatalf("ToDecodedBidBlock failed: %v", err) + } + if decoded.Sidecars == nil { + t.Fatal("nil sidecars should be normalized to an empty slice") + } + if len(decoded.Sidecars) != 0 { + t.Fatalf("sidecars length mismatch: got %d, want 0", len(decoded.Sidecars)) + } +} + +func TestBidBlockArgsToDecodedBidBlockCopiesHeader(t *testing.T) { + args := &BidBlockArgs{ + BidBlock: &BidBlock{ + Header: &types.Header{ + Difficulty: big.NewInt(1), + Number: big.NewInt(1), + Extra: []byte{1, 2, 3}, + }, + }, + } + + decoded, err := args.ToDecodedBidBlock(common.Address{0x1}) + if err != nil { + t.Fatalf("ToDecodedBidBlock failed: %v", err) + } + if decoded.Header == args.BidBlock.Header { + t.Fatal("decoded BidBlock header must not share the original header pointer") + } + + decoded.Header.Number.SetUint64(2) + decoded.Header.Extra[0] = 9 + + if args.BidBlock.Header.Number.Uint64() != 1 { + t.Fatalf("original header number mutated: got %d, want 1", args.BidBlock.Header.Number.Uint64()) + } + if args.BidBlock.Header.Extra[0] != 1 { + t.Fatalf("original header extra mutated: got %d, want 1", args.BidBlock.Header.Extra[0]) + } +} diff --git a/core/types/builder/block_mev_info.go b/core/types/builder/block_mev_info.go new file mode 100644 index 0000000000..1ed1e94ae9 --- /dev/null +++ b/core/types/builder/block_mev_info.go @@ -0,0 +1,59 @@ +// Copyright 2026 The go-ethereum Authors +// This file is part of the go-ethereum library. +// +// BEP-675 block-source tagging. Validators encode the winning MEV path and +// builder address into header.RequestsHash; local blocks keep EmptyRequestsHash. + +package builder + +import ( + "github.com/ethereum/go-ethereum/common" +) + +const blockMevInfoVersionOffset = common.HashLength - common.AddressLength - 1 // 11 + +// BlockMevInfoVersion identifies which submission path produced a block. +// Stored in header.RequestsHash at blockMevInfoVersionOffset. +type BlockMevInfoVersion uint8 + +const ( + // BlockMevInfoVersionBid identifies blocks produced via legacy SendBid. + BlockMevInfoVersionBid BlockMevInfoVersion = 1 + // BlockMevInfoVersionBidBlock identifies blocks produced via BEP-675 SendBidBlock. + BlockMevInfoVersionBidBlock BlockMevInfoVersion = 2 +) + +// EncodeBlockMevInfo packs (version, builder) into a 32-byte hash suitable for +// header.RequestsHash. Layout: +// +// [0:blockMevInfoVersionOffset] = 0 (leading-zero sentinel) +// [blockMevInfoVersionOffset] = version (1 = bid, 2 = bidblock) +// [blockMevInfoVersionOffset+1:] = builder (20-byte address) +// +// Local blocks must NOT use this encoding; they keep the default +// EmptyRequestsHash so callers can rely on "untagged" == local. +func EncodeBlockMevInfo(version BlockMevInfoVersion, builder common.Address) common.Hash { + var h common.Hash + h[blockMevInfoVersionOffset] = byte(version) + copy(h[blockMevInfoVersionOffset+1:], builder[:]) + return h +} + +// DecodeBlockMevInfo recovers the MEV source and builder from h. +// ok=false means callers should treat the block as local. +func DecodeBlockMevInfo(h common.Hash) (version BlockMevInfoVersion, builder common.Address, ok bool) { + for i := 0; i < blockMevInfoVersionOffset; i++ { + if h[i] != 0 { + return 0, common.Address{}, false + } + } + v := BlockMevInfoVersion(h[blockMevInfoVersionOffset]) + if v != BlockMevInfoVersionBid && v != BlockMevInfoVersionBidBlock { + return 0, common.Address{}, false + } + copy(builder[:], h[blockMevInfoVersionOffset+1:]) + if builder == (common.Address{}) { + return 0, common.Address{}, false + } + return v, builder, true +} diff --git a/core/types/builder/block_mev_info_test.go b/core/types/builder/block_mev_info_test.go new file mode 100644 index 0000000000..41faf4562a --- /dev/null +++ b/core/types/builder/block_mev_info_test.go @@ -0,0 +1,50 @@ +// Copyright 2026 The go-ethereum Authors +// This file is part of the go-ethereum library. + +package builder + +import ( + "testing" + + "github.com/ethereum/go-ethereum/common" +) + +func TestBlockMevInfoEncodeDecode(t *testing.T) { + builder := common.HexToAddress("0x317aB60A0815F8Db2e6cb3f302C152d2A5ef4854") + + // Round-trip: both versions encode then decode back to the same (version, builder). + t.Run("round-trip", func(t *testing.T) { + for _, v := range []BlockMevInfoVersion{BlockMevInfoVersionBid, BlockMevInfoVersionBidBlock} { + gotV, gotB, ok := DecodeBlockMevInfo(EncodeBlockMevInfo(v, builder)) + if !ok || gotV != v || gotB != builder { + t.Fatalf("version %d: got (v=%d, builder=%s, ok=%v), want (%d, %s, true)", + v, gotV, gotB.Hex(), ok, v, builder.Hex()) + } + } + }) + + // Invalid encodings must decode to ok=false (caller treats as a local/untagged block). + t.Run("invalid->ok=false", func(t *testing.T) { + nonzeroSentinel := EncodeBlockMevInfo(BlockMevInfoVersionBidBlock, builder) + nonzeroSentinel[0] = 1 // leading sentinel bytes [0:11] must all be zero + + versionTooHigh := EncodeBlockMevInfo(BlockMevInfoVersionBidBlock, builder) + versionTooHigh[blockMevInfoVersionOffset] = 3 // not 1 or 2 + + versionZero := EncodeBlockMevInfo(BlockMevInfoVersionBidBlock, builder) + versionZero[blockMevInfoVersionOffset] = 0 + + cases := map[string]common.Hash{ + "nonzero sentinel": nonzeroSentinel, + "version 3": versionTooHigh, + "version 0": versionZero, + "zero builder": EncodeBlockMevInfo(BlockMevInfoVersionBidBlock, common.Address{}), + "empty hash": {}, + } + for name, h := range cases { + if _, _, ok := DecodeBlockMevInfo(h); ok { + t.Errorf("%s: ok=true, want false", name) + } + } + }) +} diff --git a/core/vm/contracts.go b/core/vm/contracts.go index f8b2d0856d..e132467a4e 100644 --- a/core/vm/contracts.go +++ b/core/vm/contracts.go @@ -112,8 +112,8 @@ var PrecompiledContractsNano = PrecompiledContracts{ common.BytesToAddress([]byte{0x8}): &bn256PairingIstanbul{}, common.BytesToAddress([]byte{0x9}): &blake2F{}, - common.BytesToAddress([]byte{0x64}): &tmHeaderValidateNano{}, - common.BytesToAddress([]byte{0x65}): &iavlMerkleProofValidateNano{}, + common.BytesToAddress([]byte{0x64}): &tmHeaderValidateDeprecated{}, + common.BytesToAddress([]byte{0x65}): &iavlMerkleProofValidateDeprecated{}, } var PrecompiledContractsMoran = PrecompiledContracts{ @@ -350,6 +350,37 @@ var PrecompiledContractsOsaka = PrecompiledContracts{ common.BytesToAddress([]byte{0x1, 0x00}): &p256Verify{eip7951: true}, } +// PrecompiledContractsPasteur contains the set of pre-compiled Ethereum +// contracts used in the Pasteur release. +var PrecompiledContractsPasteur = PrecompiledContracts{ + common.BytesToAddress([]byte{0x01}): &ecrecover{}, + common.BytesToAddress([]byte{0x02}): &sha256hash{}, + common.BytesToAddress([]byte{0x03}): &ripemd160hash{}, + common.BytesToAddress([]byte{0x04}): &dataCopy{}, + common.BytesToAddress([]byte{0x05}): &bigModExp{eip2565: true, eip7823: true, eip7883: true}, + common.BytesToAddress([]byte{0x06}): &bn256AddIstanbul{}, + common.BytesToAddress([]byte{0x07}): &bn256ScalarMulIstanbul{}, + common.BytesToAddress([]byte{0x08}): &bn256PairingIstanbul{}, + common.BytesToAddress([]byte{0x09}): &blake2F{}, + common.BytesToAddress([]byte{0x0a}): &kzgPointEvaluation{}, + common.BytesToAddress([]byte{0x0b}): &bls12381G1Add{}, + common.BytesToAddress([]byte{0x0c}): &bls12381G1MultiExp{}, + common.BytesToAddress([]byte{0x0d}): &bls12381G2Add{}, + common.BytesToAddress([]byte{0x0e}): &bls12381G2MultiExp{}, + common.BytesToAddress([]byte{0x0f}): &bls12381Pairing{}, + common.BytesToAddress([]byte{0x10}): &bls12381MapG1{}, + common.BytesToAddress([]byte{0x11}): &bls12381MapG2{}, + + common.BytesToAddress([]byte{0x64}): &tmHeaderValidateDeprecated{}, + common.BytesToAddress([]byte{0x65}): &iavlMerkleProofValidateDeprecated{}, + common.BytesToAddress([]byte{0x66}): &blsSignatureVerify{}, + common.BytesToAddress([]byte{0x67}): &cometBFTLightBlockValidatePasteur{}, + common.BytesToAddress([]byte{0x68}): &verifyDoubleSignEvidence{}, + common.BytesToAddress([]byte{0x69}): &secp256k1SignatureRecover{}, + + common.BytesToAddress([]byte{0x1, 0x00}): &p256Verify{eip7951: true}, +} + // PrecompiledContractsP256Verify contains the precompiled Ethereum // contract specified in EIP-7212. This is exported for testing purposes. var PrecompiledContractsP256Verify = PrecompiledContracts{ @@ -357,6 +388,7 @@ var PrecompiledContractsP256Verify = PrecompiledContracts{ } var ( + PrecompiledAddressesPasteur []common.Address PrecompiledAddressesOsaka []common.Address PrecompiledAddressesPrague []common.Address PrecompiledAddressesHaber []common.Address @@ -420,12 +452,17 @@ func init() { for k := range PrecompiledContractsOsaka { PrecompiledAddressesOsaka = append(PrecompiledAddressesOsaka, k) } + for k := range PrecompiledContractsPasteur { + PrecompiledAddressesPasteur = append(PrecompiledAddressesPasteur, k) + } } func activePrecompiledContracts(rules params.Rules) PrecompiledContracts { switch { case rules.IsVerkle: return PrecompiledContractsVerkle + case rules.IsPasteur: + return PrecompiledContractsPasteur case rules.IsOsaka: return PrecompiledContractsOsaka case rules.IsPrague: @@ -467,6 +504,8 @@ func ActivePrecompiledContracts(rules params.Rules) PrecompiledContracts { // ActivePrecompiles returns the precompile addresses enabled with the current configuration. func ActivePrecompiles(rules params.Rules) []common.Address { switch { + case rules.IsPasteur: + return PrecompiledAddressesPasteur case rules.IsOsaka: return PrecompiledAddressesOsaka case rules.IsPrague: @@ -1623,6 +1662,10 @@ func (c *blsSignatureVerify) RequiredGas(input []byte) uint64 { // Run input: // msg | signature | [{bls pubkey}] | // 32 bytes | 96 bytes | [{48 bytes}] | +// +// Note: as a generic BLS signature verification primitive, this precompile +// does not require public keys to be unique. Callers that need uniqueness +// (e.g. validator set decoding) must enforce it themselves. func (c *blsSignatureVerify) Run(input []byte) ([]byte, error) { msgAndSigLength := msgHashLength + signatureLength inputLen := uint64(len(input)) diff --git a/core/vm/contracts_lightclient.go b/core/vm/contracts_lightclient.go index d83c537644..9290b818b6 100644 --- a/core/vm/contracts_lightclient.go +++ b/core/vm/contracts_lightclient.go @@ -7,6 +7,7 @@ import ( "net/url" "strings" + "github.com/cometbft/cometbft/types" "github.com/cosmos/iavl" "github.com/tendermint/tendermint/crypto/merkle" "github.com/tendermint/tendermint/crypto/secp256k1" @@ -133,33 +134,34 @@ func (c *iavlMerkleProofValidate) Name() string { return "IAVL_MERKLE_PROOF_VALIDATE" } -// tmHeaderValidateNano implemented as a native contract. -type tmHeaderValidateNano struct{} +// tmHeaderValidateDeprecated implemented as a native contract that disables the +// legacy v1 Tendermint header-validate precompile (returns an error for any input). +type tmHeaderValidateDeprecated struct{} -func (c *tmHeaderValidateNano) RequiredGas(input []byte) uint64 { +func (c *tmHeaderValidateDeprecated) RequiredGas(input []byte) uint64 { return params.TendermintHeaderValidateGas } -func (c *tmHeaderValidateNano) Run(input []byte) (result []byte, err error) { - return nil, errors.New("suspend") +func (c *tmHeaderValidateDeprecated) Run(input []byte) (result []byte, err error) { + return nil, errors.New("deprecated") } -func (c *tmHeaderValidateNano) Name() string { - return "HEADER_VALIDATE_NANO" +func (c *tmHeaderValidateDeprecated) Name() string { + return "HEADER_VALIDATE_DEPRECATED" } -type iavlMerkleProofValidateNano struct{} +type iavlMerkleProofValidateDeprecated struct{} -func (c *iavlMerkleProofValidateNano) RequiredGas(_ []byte) uint64 { +func (c *iavlMerkleProofValidateDeprecated) RequiredGas(_ []byte) uint64 { return params.IAVLMerkleProofValidateGas } -func (c *iavlMerkleProofValidateNano) Run(_ []byte) (result []byte, err error) { - return nil, errors.New("suspend") +func (c *iavlMerkleProofValidateDeprecated) Run(_ []byte) (result []byte, err error) { + return nil, errors.New("deprecated") } -func (c *iavlMerkleProofValidateNano) Name() string { - return "IAVL_MERKLE_PROOF_VALIDATE_NANO" +func (c *iavlMerkleProofValidateDeprecated) Name() string { + return "IAVL_MERKLE_PROOF_VALIDATE_DEPRECATED" } // ------------------------------------------------------------------------------------------------------------------------------------------------ @@ -391,14 +393,18 @@ func (c *cometBFTLightBlockValidate) RequiredGas(input []byte) uint64 { return params.CometBFTLightBlockValidateGas } -func (c *cometBFTLightBlockValidate) run(input []byte, isHertz bool) (result []byte, err error) { +func (c *cometBFTLightBlockValidate) run(input []byte, isHertz bool, requireUniqueValidators bool) (result []byte, err error) { defer func() { if r := recover(); r != nil { err = fmt.Errorf("internal error: %v\n", r) } }() - cs, block, err := v2.DecodeLightBlockValidationInput(input) + var ( + cs *v2.ConsensusState + block *types.LightBlock + ) + cs, block, err = v2.DecodeLightBlockValidationInput(input, requireUniqueValidators) if err != nil { return nil, err } @@ -418,7 +424,7 @@ func (c *cometBFTLightBlockValidate) run(input []byte, isHertz bool) (result []b } func (c *cometBFTLightBlockValidate) Run(input []byte) (result []byte, err error) { - return c.run(input, false) + return c.run(input, false, false) } func (c *cometBFTLightBlockValidate) Name() string { @@ -430,13 +436,30 @@ type cometBFTLightBlockValidateHertz struct { } func (c *cometBFTLightBlockValidateHertz) Run(input []byte) (result []byte, err error) { - return c.run(input, true) + return c.run(input, true, false) } func (c *cometBFTLightBlockValidateHertz) Name() string { return "COMET_BFT_LIGHT_BLOCK_VALIDATE_HERTZ" } +type cometBFTLightBlockValidatePasteur struct { + cometBFTLightBlockValidate +} + +// Price per input byte so cost scales with the validator/signature count. +func (c *cometBFTLightBlockValidatePasteur) RequiredGas(input []byte) uint64 { + return params.CometBFTLightBlockValidateGas + uint64(len(input))*params.CometBFTLightBlockValidatePerByteGas +} + +func (c *cometBFTLightBlockValidatePasteur) Run(input []byte) (result []byte, err error) { + return c.run(input, true, true) +} + +func (c *cometBFTLightBlockValidatePasteur) Name() string { + return "COMET_BFT_LIGHT_BLOCK_VALIDATE_PASTEUR" +} + // secp256k1SignatureRecover implemented as a native contract. type secp256k1SignatureRecover struct{} diff --git a/core/vm/contracts_lightclient_test.go b/core/vm/contracts_lightclient_test.go index e3211b07da..ceb8bbe0c9 100644 --- a/core/vm/contracts_lightclient_test.go +++ b/core/vm/contracts_lightclient_test.go @@ -5,13 +5,17 @@ import ( "encoding/hex" "testing" + "github.com/cometbft/cometbft/types" "github.com/cosmos/iavl" + "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/params" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" "github.com/tendermint/tendermint/crypto/merkle" cmn "github.com/tendermint/tendermint/libs/common" v1 "github.com/ethereum/go-ethereum/core/vm/lightclient/v1" + v2 "github.com/ethereum/go-ethereum/core/vm/lightclient/v2" ) const ( @@ -374,6 +378,39 @@ func TestCometBFTLightBlockValidateHertz(t *testing.T) { require.Equal(t, expectOutputStr, hex.EncodeToString(res)) } +func TestCometBFTLightBlockValidateRejectsDuplicateTrustedValidatorsAtPasteur(t *testing.T) { + inputStr := "000000000000000000000000000000000000000000000000000000000000018c677265656e6669656c645f393030302d3132310000000000000000000000000000000000000000013c350cd55b99dc6c2b7da9bef5410fbfb869fede858e7b95bf7ca294e228bb40e33f6e876d63791ebd05ff617a1b4f4ad1aa2ce65e3c3a9cdfb33e0ffa7e8423000000000098968015154514f68ce65a0d9eecc578c0ab12da0a2a28a0805521b5b7ae56eb3fb24555efbfe59e1622bfe9f7be8c9022e9b3f2442739c1ce870b9adee169afe60f674edd7c86451c5363d89052fde8351895eeea166ce5373c36e31b518ed191d0c599aa0f5b0000000000989680432f6c4908a9aa5f3444421f466b11645235c99b831b2a2de9e504d7ea299e52a202ce529808618eb3bfc0addf13d8c5f2df821d81e18f9bc61583510b322d067d46323b0a572635c06a049c0a2a929e3c8184a50cf6a8b95708c25834ade456f399015a0000000000989680864cb9828254d712f8e59b164fc6a9402dc4e6c59065e38cff24f5323c8c5da888a0f97e5ee4ba1e11b0674b0a0d06204c1dfa247c370cd4be3e799fc4f6f48d977ac7ca0aeb060adb030a02080b1213677265656e6669656c645f393030302d3132311802220c08b2d7f3a10610e8d2adb3032a480a20ec6ecb5db4ffb17fabe40c60ca7b8441e9c5d77585d0831186f3c37aa16e9c15122408011220a2ab9e1eb9ea52812f413526e424b326aff2f258a56e00d690db9f805b60fe7e32200f40aeff672e8309b7b0aefbb9a1ae3d4299b5c445b7d54e8ff398488467f0053a20e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b85542203c350cd55b99dc6c2b7da9bef5410fbfb869fede858e7b95bf7ca294e228bb404a203c350cd55b99dc6c2b7da9bef5410fbfb869fede858e7b95bf7ca294e228bb405220294d8fbd0b94b767a7eba9840f299a3586da7fe6b5dead3b7eecba193c400f935a20bc50557c12d7392b0d07d75df0b61232d48f86a74fdea6d1485d9be6317d268c6220e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b8556a20e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b85572146699336aa109d1beab3946198c8e59f3b2cbd92f7a4065e3cd89e315ca39d87dee92835b98f8b8ec0861d6d9bb2c60156df5d375b3ceb1fbe71af6a244907d62548a694165caa660fec7a9b4e7b9198191361c71be0b128a0308021a480a20726abd0fdbfb6f779b0483e6e4b4b6f12241f6ea2bf374233ab1a316692b6415122408011220159f10ff15a8b58fc67a92ffd7f33c8cd407d4ce81b04ca79177dfd00ca19a67226808021214050cff76cc632760ba9db796c046004c900967361a0c08b3d7f3a10610808cadba03224080713027ffb776a702d78fd0406205c629ba473e1f8d6af646190f6eb9262cd67d69be90d10e597b91e06d7298eb6fa4b8f1eb7752ebf352a1f51560294548042268080212146699336aa109d1beab3946198c8e59f3b2cbd92f1a0c08b3d7f3a10610b087c1c00322405e2ddb70acfe4904438be3d9f4206c0ace905ac4fc306a42cfc9e86268950a0fbfd6ec5f526d3e41a3ef52bf9f9f358e3cb4c3feac76c762fa3651c1244fe004226808021214c55765fd2d0570e869f6ac22e7f2916a35ea300d1a0c08b3d7f3a10610f0b3d492032240ca17898bd22232fc9374e1188636ee321a396444a5b1a79f7628e4a11f265734b2ab50caf21e8092c55d701248e82b2f011426cb35ba22043b497a6b4661930612a0050aa8010a14050cff76cc632760ba9db796c046004c9009673612220a20e33f6e876d63791ebd05ff617a1b4f4ad1aa2ce65e3c3a9cdfb33e0ffa7e84231880ade2042080a6bbf6ffffffffff012a30a0805521b5b7ae56eb3fb24555efbfe59e1622bfe9f7be8c9022e9b3f2442739c1ce870b9adee169afe60f674edd7c86321415154514f68ce65a0d9eecc578c0ab12da0a2a283a14ee7a2a6a44d427f6949eeb8f12ea9fbb2501da880aa2010a146699336aa109d1beab3946198c8e59f3b2cbd92f12220a20451c5363d89052fde8351895eeea166ce5373c36e31b518ed191d0c599aa0f5b1880ade2042080ade2042a30831b2a2de9e504d7ea299e52a202ce529808618eb3bfc0addf13d8c5f2df821d81e18f9bc61583510b322d067d46323b3214432f6c4908a9aa5f3444421f466b11645235c99b3a14a0a7769429468054e19059af4867da0a495567e50aa2010a14c55765fd2d0570e869f6ac22e7f2916a35ea300d12220a200a572635c06a049c0a2a929e3c8184a50cf6a8b95708c25834ade456f399015a1880ade2042080ade2042a309065e38cff24f5323c8c5da888a0f97e5ee4ba1e11b0674b0a0d06204c1dfa247c370cd4be3e799fc4f6f48d977ac7ca3214864cb9828254d712f8e59b164fc6a9402dc4e6c53a143139916d97df0c589312b89950b6ab9795f34d1a12a8010a14050cff76cc632760ba9db796c046004c9009673612220a20e33f6e876d63791ebd05ff617a1b4f4ad1aa2ce65e3c3a9cdfb33e0ffa7e84231880ade2042080a6bbf6ffffffffff012a30a0805521b5b7ae56eb3fb24555efbfe59e1622bfe9f7be8c9022e9b3f2442739c1ce870b9adee169afe60f674edd7c86321415154514f68ce65a0d9eecc578c0ab12da0a2a283a14ee7a2a6a44d427f6949eeb8f12ea9fbb2501da88" + + input, err := hex.DecodeString(inputStr) + require.NoError(t, err) + + cs, block, err := v2.DecodeLightBlockValidationInput(input, false) + require.NoError(t, err) + + duplicate := cs.ValidatorSet.Validators[0].Copy() + cs.ValidatorSet = &types.ValidatorSet{Validators: []*types.Validator{duplicate.Copy(), duplicate.Copy(), duplicate.Copy()}} + csBytes, err := cs.EncodeConsensusState() + require.NoError(t, err) + + blockProto, err := block.ToProto() + require.NoError(t, err) + blockBytes, err := blockProto.Marshal() + require.NoError(t, err) + + mutatedInput := make([]byte, 32) + binary.BigEndian.PutUint64(mutatedInput[24:], uint64(len(csBytes))) + mutatedInput = append(mutatedInput, csBytes...) + mutatedInput = append(mutatedInput, blockBytes...) + + pasteurPrecompile := ActivePrecompiledContracts(params.Rules{IsOsaka: true, IsMendel: true, IsPasteur: true})[common.BytesToAddress([]byte{0x67})] + _, err = pasteurPrecompile.Run(mutatedInput) + require.ErrorContains(t, err, "duplicate validator") + + legacyPrecompile := ActivePrecompiledContracts(params.Rules{IsOsaka: true})[common.BytesToAddress([]byte{0x67})] + _, err = legacyPrecompile.Run(mutatedInput) + require.NoError(t, err) +} + func TestSecp256k1SignatureRecover(t *testing.T) { // local key { diff --git a/core/vm/contracts_test.go b/core/vm/contracts_test.go index 684a51080a..4e182425d1 100644 --- a/core/vm/contracts_test.go +++ b/core/vm/contracts_test.go @@ -25,6 +25,7 @@ import ( "time" "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/params" ) // precompiledTest defines the input/output pairs for precompiled contract tests. @@ -353,6 +354,25 @@ func TestPrecompiledBLS12381MapG2(t *testing.T) { testJson("blsMapG2", "f10 func TestPrecompiledBlsSignatureVerify(t *testing.T) { testJson("blsSignatureVerify", "66", t) } +func TestActivePrecompiledContractsUsesPasteurVariants(t *testing.T) { + rules := params.Rules{IsOsaka: true, IsMendel: true, IsPasteur: true} + precompiles := ActivePrecompiledContracts(rules) + + requirePrecompile := func(addr byte) PrecompiledContract { + t.Helper() + + precompile, ok := precompiles[common.BytesToAddress([]byte{addr})] + if !ok { + t.Fatalf("missing precompile 0x%02x", addr) + } + return precompile + } + + if got := requirePrecompile(0x67).Name(); got != "COMET_BFT_LIGHT_BLOCK_VALIDATE_PASTEUR" { + t.Fatalf("unexpected Pasteur 0x67 precompile: %s", got) + } +} + func TestPrecompiledPointEvaluation(t *testing.T) { testJson("pointEvaluation", "0a", t) } func BenchmarkPrecompiledPointEvaluation(b *testing.B) { benchJson("pointEvaluation", "0a", b) } diff --git a/core/vm/interpreter.go b/core/vm/interpreter.go index 259f1379e7..e796d31350 100644 --- a/core/vm/interpreter.go +++ b/core/vm/interpreter.go @@ -29,14 +29,12 @@ import ( // Config are the configuration options for the Interpreter type Config struct { - Tracer *tracing.Hooks + Tracer *tracing.Hooks + NoBaseFee bool // Forces the EIP-1559 baseFee to 0 (needed for 0 price calls) EnablePreimageRecording bool // Enables recording of SHA3/keccak preimages ExtraEips []int // Additional EIPS that are to be enabled EnableOpcodeOptimizations bool // Enable opcode optimization - - StatelessSelfValidation bool // Generate execution witnesses and self-check against them (testing purpose) - EnableWitnessStats bool // Whether trie access statistics collection is enabled } // ScopeContext contains the things that are per-call, such as stack and memory, diff --git a/core/vm/lightclient/v2/lightclient.go b/core/vm/lightclient/v2/lightclient.go index b531e29111..9ab4b7d0c5 100644 --- a/core/vm/lightclient/v2/lightclient.go +++ b/core/vm/lightclient/v2/lightclient.go @@ -36,6 +36,81 @@ type ConsensusState struct { ValidatorSet *types.ValidatorSet } +type validatorDuplicateTracker struct { + field string + seen map[string]int + ignoreZero bool +} + +func newValidatorDuplicateTracker(field string, size int, ignoreZero bool) *validatorDuplicateTracker { + return &validatorDuplicateTracker{ + field: field, + seen: make(map[string]int, size), + ignoreZero: ignoreZero, + } +} + +func (t *validatorDuplicateTracker) check(idx int, value []byte) error { + if t.ignoreZero { + // Optional bridge fields may be omitted in source validators or zero-filled by + // fixed-width decoding. Both forms mean "unset" and should not count as duplicates. + if len(value) == 0 || isZeroBytes(value) { + return nil + } + } + + key := string(value) + if firstIdx, ok := t.seen[key]; ok { + return fmt.Errorf("duplicate validator %s #%d and #%d: %X", t.field, firstIdx, idx, value) + } + t.seen[key] = idx + return nil +} + +func isZeroBytes(value []byte) bool { + if len(value) == 0 { + return false + } + for _, b := range value { + if b != 0 { + return false + } + } + return true +} + +func validateUniqueValidatorSet(validatorSet *types.ValidatorSet) error { + if validatorSet == nil { + return nil + } + + size := len(validatorSet.Validators) + addresses := newValidatorDuplicateTracker("address", size, false) + pubKeys := newValidatorDuplicateTracker("pubkey", size, false) + blsKeys := newValidatorDuplicateTracker("bls key", size, true) + relayerAddresses := newValidatorDuplicateTracker("relayer address", size, true) + + for idx, validator := range validatorSet.Validators { + if validator == nil || validator.PubKey == nil { + return fmt.Errorf("invalid validator #%d", idx) + } + if err := addresses.check(idx, validator.Address); err != nil { + return err + } + if err := pubKeys.check(idx, validator.PubKey.Bytes()); err != nil { + return err + } + if err := blsKeys.check(idx, validator.BlsKey); err != nil { + return err + } + if err := relayerAddresses.check(idx, validator.RelayerAddress); err != nil { + return err + } + } + + return nil +} + // output: // | chainID | height | nextValidatorSetHash | [{validator pubkey, voting power, relayer address, relayer bls pubkey}] | // | 32 bytes | 8 bytes | 32 bytes | [{32 bytes, 8 bytes, 20 bytes, 48 bytes}] | @@ -137,7 +212,7 @@ func (cs *ConsensusState) ApplyLightBlock(block *types.LightBlock, isHertz bool) // input: // | chainID | height | nextValidatorSetHash | [{validator pubkey, voting power, relayer address, relayer bls pubkey}] | // | 32 bytes | 8 bytes | 32 bytes | [{32 bytes, 8 bytes, 20 bytes, 48 bytes}] | -func DecodeConsensusState(input []byte) (ConsensusState, error) { +func DecodeConsensusState(input []byte, requireUniqueValidators bool) (ConsensusState, error) { minimumLength := chainIDLength + heightLength + validatorSetHashLength inputLen := uint64(len(input)) if inputLen <= minimumLength || (inputLen-minimumLength)%singleValidatorBytesLength != 0 { @@ -192,6 +267,11 @@ func DecodeConsensusState(input []byte) (ConsensusState, error) { Validators: validatorSet, }, } + if requireUniqueValidators { + if err := validateUniqueValidatorSet(consensusState.ValidatorSet); err != nil { + return ConsensusState{}, err + } + } return consensusState, nil } @@ -199,7 +279,7 @@ func DecodeConsensusState(input []byte) (ConsensusState, error) { // input: // consensus state length | consensus state | light block | // 32 bytes | | | -func DecodeLightBlockValidationInput(input []byte) (*ConsensusState, *types.LightBlock, error) { +func DecodeLightBlockValidationInput(input []byte, requireUniqueValidators bool) (*ConsensusState, *types.LightBlock, error) { if uint64(len(input)) <= consensusStateLengthBytesLength { return nil, nil, errors.New("invalid input") } @@ -214,7 +294,7 @@ func DecodeLightBlockValidationInput(input []byte) (*ConsensusState, *types.Ligh return nil, nil, fmt.Errorf("expected payload size %d, actual size: %d", consensusStateLengthBytesLength+csLen, len(input)) } - cs, err := DecodeConsensusState(input[consensusStateLengthBytesLength : consensusStateLengthBytesLength+csLen]) + cs, err := DecodeConsensusState(input[consensusStateLengthBytesLength:consensusStateLengthBytesLength+csLen], requireUniqueValidators) if err != nil { return nil, nil, err } @@ -228,6 +308,11 @@ func DecodeLightBlockValidationInput(input []byte) (*ConsensusState, *types.Ligh if err != nil { return nil, nil, err } + if requireUniqueValidators { + if err := validateUniqueValidatorSet(block.ValidatorSet); err != nil { + return nil, nil, err + } + } return &cs, block, nil } diff --git a/core/vm/lightclient/v2/lightclient_test.go b/core/vm/lightclient/v2/lightclient_test.go index 0a7d43f525..9c7bfae833 100644 --- a/core/vm/lightclient/v2/lightclient_test.go +++ b/core/vm/lightclient/v2/lightclient_test.go @@ -3,6 +3,7 @@ package v2 import ( "bytes" + "encoding/binary" "encoding/hex" "testing" @@ -144,7 +145,7 @@ func TestDecodeConsensusState(t *testing.T) { csBytes, err := hex.DecodeString(testcase.consensusStateBytes) require.NoError(t, err) - cs, err := DecodeConsensusState(csBytes) + cs, err := DecodeConsensusState(csBytes, false) require.NoError(t, err) if cs.ChainID != testcase.chainID { @@ -182,7 +183,7 @@ func TestConsensusStateApplyLightBlock(t *testing.T) { block, err := types.LightBlockFromProto(&lbpb) require.NoError(t, err) - cs, err := DecodeConsensusState(csBytes) + cs, err := DecodeConsensusState(csBytes, false) require.NoError(t, err) validatorSetChanged, err := cs.ApplyLightBlock(block, true) require.NoError(t, err) @@ -196,3 +197,125 @@ func TestConsensusStateApplyLightBlock(t *testing.T) { } } } + +func TestDecodeConsensusStateWithValidationRejectsDuplicateValidators(t *testing.T) { + csBytes, err := hex.DecodeString(testcases[0].consensusStateBytes) + require.NoError(t, err) + + validatorBytes := csBytes[chainIDLength+heightLength+validatorSetHashLength:] + duplicateConsensusState := append([]byte{}, csBytes[:chainIDLength+heightLength+validatorSetHashLength]...) + duplicateConsensusState = append(duplicateConsensusState, validatorBytes...) + duplicateConsensusState = append(duplicateConsensusState, validatorBytes...) + + _, err = DecodeConsensusState(duplicateConsensusState, true) + require.ErrorContains(t, err, "duplicate validator") +} + +func TestValidateUniqueValidatorSetRejectsDuplicateBridgeKeys(t *testing.T) { + makeValidator := func(info validatorInfo) *types.Validator { + t.Helper() + + pubKeyBytes, err := hex.DecodeString(info.pubKey) + require.NoError(t, err) + relayerAddress, err := hex.DecodeString(info.relayerAddress) + require.NoError(t, err) + relayerBlsKey, err := hex.DecodeString(info.relayerBlsKey) + require.NoError(t, err) + + pubkey := ed25519.PubKey(make([]byte, ed25519.PubKeySize)) + copy(pubkey[:], pubKeyBytes) + validator := types.NewValidator(pubkey, info.votingPower) + validator.SetRelayerAddress(relayerAddress) + validator.SetBlsKey(relayerBlsKey) + return validator + } + + t.Run("duplicate bls key", func(t *testing.T) { + first := makeValidator(testcases[1].vals[0]) + second := makeValidator(testcases[1].vals[1]) + second.SetBlsKey(append([]byte{}, first.BlsKey...)) + + err := validateUniqueValidatorSet(&types.ValidatorSet{Validators: []*types.Validator{first, second}}) + require.ErrorContains(t, err, "duplicate validator bls key") + }) + + t.Run("duplicate relayer address", func(t *testing.T) { + first := makeValidator(testcases[1].vals[0]) + second := makeValidator(testcases[1].vals[1]) + second.SetRelayerAddress(append([]byte{}, first.RelayerAddress...)) + + err := validateUniqueValidatorSet(&types.ValidatorSet{Validators: []*types.Validator{first, second}}) + require.ErrorContains(t, err, "duplicate validator relayer address") + }) +} + +func TestDecodeConsensusStateWithValidationAllowsUnsetBridgeKeys(t *testing.T) { + makeValidator := func(seed byte) *types.Validator { + t.Helper() + + pubkey := ed25519.PubKey(make([]byte, ed25519.PubKeySize)) + for i := range pubkey { + pubkey[i] = seed + byte(i) + 1 + } + + return types.NewValidator(pubkey, 100) + } + + consensusState := ConsensusState{ + ChainID: "chain_9000-121", + Height: 1, + NextValidatorSetHash: bytes.Repeat([]byte{0xAB}, int(validatorSetHashLength)), + ValidatorSet: &types.ValidatorSet{ + Validators: []*types.Validator{ + makeValidator(0x01), + makeValidator(0x02), + }, + }, + } + + csBytes, err := consensusState.EncodeConsensusState() + require.NoError(t, err) + + _, err = DecodeConsensusState(csBytes, true) + require.NoError(t, err) +} + +func TestIsZeroBytesRequiresNonEmptyInput(t *testing.T) { + require.False(t, isZeroBytes(nil)) + require.False(t, isZeroBytes([]byte{})) + require.True(t, isZeroBytes([]byte{0x00, 0x00})) + require.False(t, isZeroBytes([]byte{0x00, 0x01})) +} + +func TestDecodeLightBlockValidationInputAllowsUnsetBlockBridgeKeys(t *testing.T) { + csBytes, err := hex.DecodeString(applyBlocksTestcases[0].consensusStateBytes) + require.NoError(t, err) + + blockBytes, err := hex.DecodeString(applyBlocksTestcases[0].lightBlockBytes) + require.NoError(t, err) + + var lbpb tmproto.LightBlock + err = lbpb.Unmarshal(blockBytes) + require.NoError(t, err) + + block, err := types.LightBlockFromProto(&lbpb) + require.NoError(t, err) + + for _, validator := range block.ValidatorSet.Validators { + validator.SetBlsKey(nil) + validator.SetRelayerAddress(nil) + } + + blockProto, err := block.ToProto() + require.NoError(t, err) + blockBytes, err = blockProto.Marshal() + require.NoError(t, err) + + input := make([]byte, consensusStateLengthBytesLength) + binary.BigEndian.PutUint64(input[consensusStateLengthBytesLength-uint64TypeLength:], uint64(len(csBytes))) + input = append(input, csBytes...) + input = append(input, blockBytes...) + + _, _, err = DecodeLightBlockValidationInput(input, true) + require.NoError(t, err) +} diff --git a/core/vm/precompile_pasteur_test.go b/core/vm/precompile_pasteur_test.go new file mode 100644 index 0000000000..eed827c08d --- /dev/null +++ b/core/vm/precompile_pasteur_test.go @@ -0,0 +1,62 @@ +package vm + +import ( + "testing" + + "github.com/ethereum/go-ethereum/common" +) + +// 0x64/0x65 are deprecated from Pasteur; 0x67 switches to a per-byte-priced variant. +func TestPasteurSuspendsLegacyTendermintPrecompiles(t *testing.T) { + addr64 := common.BytesToAddress([]byte{0x64}) + addr65 := common.BytesToAddress([]byte{0x65}) + + // Under Pasteur, 0x64/0x65 return "deprecated" for any input. + for _, addr := range []common.Address{addr64, addr65} { + p := PrecompiledContractsPasteur[addr] + if p == nil { + t.Fatalf("%s missing from Pasteur precompile set", addr.Hex()) + } + if _, err := p.Run([]byte("x")); err == nil || err.Error() != "deprecated" { + t.Fatalf("%s under Pasteur: expected deprecated error, got %v", addr.Hex(), err) + } + } + + // Pre-Pasteur (Osaka) they are still the live, active implementations. + if _, ok := PrecompiledContractsOsaka[addr64].(*tmHeaderValidate); !ok { + t.Fatalf("0x64 must remain active (tmHeaderValidate) pre-Pasteur") + } + if _, ok := PrecompiledContractsOsaka[addr65].(*iavlMerkleProofValidatePlato); !ok { + t.Fatalf("0x65 must remain active (iavlMerkleProofValidatePlato) pre-Pasteur") + } + + // 0x67 stays active but switches to the per-byte-priced Pasteur variant + // (Hertz/flat-gas pre-Pasteur, for replay of earlier blocks). + addr67 := common.BytesToAddress([]byte{0x67}) + if _, ok := PrecompiledContractsPasteur[addr67].(*cometBFTLightBlockValidatePasteur); !ok { + t.Fatalf("0x67 must be the Pasteur variant under Pasteur") + } + if _, ok := PrecompiledContractsOsaka[addr67].(*cometBFTLightBlockValidateHertz); !ok { + t.Fatalf("0x67 must remain the Hertz variant pre-Pasteur") + } + + // The still-needed precompiles (0x66, 0x68, 0x69) remain present under Pasteur. + for _, b := range []byte{0x66, 0x68, 0x69} { + addr := common.BytesToAddress([]byte{b}) + if PrecompiledContractsPasteur[addr] == nil { + t.Fatalf("%s must remain present under Pasteur", addr.Hex()) + } + } + + // 0x67 gas scales with input size under Pasteur, but is flat pre-Pasteur. + small := make([]byte, 1024) + large := make([]byte, 16*1024) + pasteur67 := PrecompiledContractsPasteur[addr67] + if pasteur67.RequiredGas(large) <= pasteur67.RequiredGas(small) { + t.Fatalf("Pasteur 0x67 gas must scale with input size") + } + osaka67 := PrecompiledContractsOsaka[addr67] + if osaka67.RequiredGas(large) != osaka67.RequiredGas(small) { + t.Fatalf("pre-Pasteur 0x67 gas must stay flat") + } +} diff --git a/crypto/signature_nocgo.go b/crypto/signature_nocgo.go index 25ef01b3ed..de345c32e9 100644 --- a/crypto/signature_nocgo.go +++ b/crypto/signature_nocgo.go @@ -39,6 +39,9 @@ func Ecrecover(hash, sig []byte) ([]byte, error) { } func sigToPub(hash, sig []byte) (*secp256k1.PublicKey, error) { + if len(hash) != DigestLength { + return nil, fmt.Errorf("hash is required to be exactly %d bytes (%d)", DigestLength, len(hash)) + } if len(sig) != SignatureLength { return nil, errors.New("invalid signature") } @@ -99,7 +102,7 @@ func Sign(hash []byte, prv *ecdsa.PrivateKey) ([]byte, error) { // The public key should be in compressed (33 bytes) or uncompressed (65 bytes) format. // The signature should have the 64 byte [R || S] format. func VerifySignature(pubkey, hash, signature []byte) bool { - if len(signature) != 64 { + if len(signature) != 64 || len(hash) != DigestLength { return false } var r, s secp256k1.ModNScalar diff --git a/eth/api_admin.go b/eth/api_admin.go index 4a3ccb84e8..0a8be2ed33 100644 --- a/eth/api_admin.go +++ b/eth/api_admin.go @@ -24,6 +24,7 @@ import ( "os" "strings" + "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/core" "github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/rlp" @@ -141,3 +142,7 @@ func (api *AdminAPI) ImportChain(file string) (bool, error) { } return true, nil } + +func (api *AdminAPI) SetBidBlockPermission(builder common.Address, allowed bool) { + api.eth.Miner().SetBidBlockPermission(builder, allowed) +} diff --git a/eth/api_backend.go b/eth/api_backend.go index 281eb989d5..be02b11de7 100644 --- a/eth/api_backend.go +++ b/eth/api_backend.go @@ -36,6 +36,7 @@ import ( "github.com/ethereum/go-ethereum/core/txpool" "github.com/ethereum/go-ethereum/core/txpool/locals" "github.com/ethereum/go-ethereum/core/types" + buildertypes "github.com/ethereum/go-ethereum/core/types/builder" "github.com/ethereum/go-ethereum/core/vm" "github.com/ethereum/go-ethereum/eth/downloader" "github.com/ethereum/go-ethereum/eth/gasprice" @@ -542,7 +543,7 @@ func (b *EthAPIBackend) MevRunning() bool { return b.Miner().MevRunning() } -func (b *EthAPIBackend) MevParams() *types.MevParams { +func (b *EthAPIBackend) MevParams() *buildertypes.MevParams { return b.Miner().MevParams() } @@ -566,10 +567,18 @@ func (b *EthAPIBackend) HasBuilder(builder common.Address) bool { return b.Miner().HasBuilder(builder) } -func (b *EthAPIBackend) SendBid(ctx context.Context, bid *types.BidArgs) (common.Hash, error) { +func (b *EthAPIBackend) GetBidBlockPermission(builder common.Address) buildertypes.BidBlockPermissionStatus { + return b.Miner().GetBidBlockPermission(builder) +} + +func (b *EthAPIBackend) SendBid(ctx context.Context, bid *buildertypes.BidArgs) (common.Hash, error) { return b.Miner().SendBid(ctx, bid) } +func (b *EthAPIBackend) SendBidBlock(ctx context.Context, args *buildertypes.BidBlockArgs) (common.Hash, error) { + return b.Miner().SendBidBlock(ctx, args) +} + func (b *EthAPIBackend) MinerInTurn() bool { return b.Miner().InTurn() } diff --git a/eth/api_debug.go b/eth/api_debug.go index 63cfa0ea23..ed4d4b63d4 100644 --- a/eth/api_debug.go +++ b/eth/api_debug.go @@ -24,6 +24,7 @@ import ( "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/common/hexutil" + "github.com/ethereum/go-ethereum/core" "github.com/ethereum/go-ethereum/core/rawdb" "github.com/ethereum/go-ethereum/core/state" "github.com/ethereum/go-ethereum/core/stateless" @@ -496,39 +497,23 @@ func (api *DebugAPI) StateSize(blockHashOrNumber *rpc.BlockNumberOrHash) (interf }, nil } -func (api *DebugAPI) ExecutionWitness(bn rpc.BlockNumber) (*stateless.ExtWitness, error) { +func (api *DebugAPI) ExecutionWitness(bn rpc.BlockNumberOrHash) (*stateless.ExtWitness, error) { bc := api.eth.blockchain - block, err := api.eth.APIBackend.BlockByNumber(context.Background(), bn) - if err != nil { - return &stateless.ExtWitness{}, fmt.Errorf("block number %v not found", bn) + block, err := api.eth.APIBackend.BlockByNumberOrHash(context.Background(), bn) + if block == nil || err != nil { + return &stateless.ExtWitness{}, fmt.Errorf("block %v not found", bn) } parent := bc.GetHeader(block.ParentHash(), block.NumberU64()-1) if parent == nil { - return &stateless.ExtWitness{}, fmt.Errorf("block number %v found, but parent missing", bn) - } - - result, err := bc.ProcessBlock(parent.Root, block, false, true) - if err != nil { - return nil, err - } - - return result.Witness().ToExtWitness(), nil -} - -func (api *DebugAPI) ExecutionWitnessByHash(hash common.Hash) (*stateless.ExtWitness, error) { - bc := api.eth.blockchain - block := bc.GetBlockByHash(hash) - if block == nil { - return &stateless.ExtWitness{}, fmt.Errorf("block hash %x not found", hash) + return &stateless.ExtWitness{}, fmt.Errorf("block %v found, but parent missing", bn) } - - parent := bc.GetHeader(block.ParentHash(), block.NumberU64()-1) - if parent == nil { - return &stateless.ExtWitness{}, fmt.Errorf("block number %x found, but parent missing", hash) + config := core.ExecuteConfig{ + WriteState: false, + EnableTracer: false, + MakeWitness: true, } - - result, err := bc.ProcessBlock(parent.Root, block, false, true) + result, err := bc.ProcessBlock(context.Background(), parent.Root, block, config) if err != nil { return nil, err } diff --git a/eth/api_miner.go b/eth/api_miner.go index 64b3130dae..524056b289 100644 --- a/eth/api_miner.go +++ b/eth/api_miner.go @@ -20,8 +20,6 @@ import ( "math/big" "time" - "github.com/ethereum/go-ethereum/params" - "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/common/hexutil" ) @@ -70,15 +68,6 @@ func (api *MinerAPI) SetGasPrice(gasPrice hexutil.Big) bool { return true } -// 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.SystemTxsGasSoftLimit { - api.e.TxPool().SetMaxGas(uint64(gasLimit) - params.SystemTxsGasSoftLimit) - } - return true -} - // SetEtherbase sets the etherbase of the miner. func (api *MinerAPI) SetEtherbase(etherbase common.Address) bool { api.e.SetEtherbase(etherbase) diff --git a/eth/backend.go b/eth/backend.go index b50d3f61fd..9ef779e409 100644 --- a/eth/backend.go +++ b/eth/backend.go @@ -76,7 +76,6 @@ import ( const ( ChainDBNamespace = "eth/db/chaindata/" - JournalFileName = "trie.journal" ChainData = "chaindata" ) @@ -177,7 +176,7 @@ func New(stack *node.Node, config *ethconfig.Config) (*Ethereum, error) { config.Miner.GasPrice = new(big.Int).Set(ethconfig.Defaults.Miner.GasPrice) } - chainDb, err := stack.OpenAndMergeDatabase(ChainData, ChainDBNamespace, false, config) + chainDb, err := stack.OpenDatabaseWithFreezer(ChainData, config.DatabaseCache, config.DatabaseHandles, config.DatabaseFreezer, ChainDBNamespace, false) if err != nil { return nil, err } @@ -261,6 +260,10 @@ func New(stack *node.Node, config *ethconfig.Config) (*Ethereum, error) { chainConfig.MendelTime = config.OverrideMendel overrides.OverrideMendel = config.OverrideMendel } + if config.OverridePasteur != nil { + chainConfig.PasteurTime = config.OverridePasteur + overrides.OverridePasteur = config.OverridePasteur + } if config.OverrideBPO1 != nil { chainConfig.BPO1Time = config.OverrideBPO1 overrides.OverrideBPO1 = config.OverrideBPO1 @@ -269,10 +272,6 @@ func New(stack *node.Node, config *ethconfig.Config) (*Ethereum, error) { chainConfig.BPO2Time = config.OverrideBPO2 overrides.OverrideBPO2 = config.OverrideBPO2 } - if config.OverridePasteur != nil { - chainConfig.PasteurTime = config.OverridePasteur - overrides.OverridePasteur = config.OverridePasteur - } if config.OverrideVerkle != nil { chainConfig.VerkleTime = config.OverrideVerkle overrides.OverrideVerkle = config.OverrideVerkle @@ -336,16 +335,10 @@ func New(stack *node.Node, config *ethconfig.Config) (*Ethereum, error) { } } - path := ChainData - if stack.CheckIfMultiDataBase() { - path = ChainData + "/state" - } - journalFilePath := stack.ResolvePath(path) + "/" + JournalFileName var ( options = &core.BlockChainConfig{ TrieCleanLimit: config.TrieCleanCache, NoPrefetch: config.NoPrefetch, - EnableBAL: config.EnableBAL, TrieDirtyLimit: config.TrieDirtyCache, ArchiveMode: config.NoPruning, TrieTimeLimit: config.TrieTimeout, @@ -356,7 +349,6 @@ func New(stack *node.Node, config *ethconfig.Config) (*Ethereum, error) { StateHistory: config.StateHistory, StateScheme: config.StateScheme, PathSyncFlush: config.PathSyncFlush, - JournalFilePath: journalFilePath, EnableIncr: config.EnableIncrSnapshots, IncrHistoryPath: config.IncrSnapshotPath, IncrHistory: config.IncrSnapshotBlockInterval, @@ -368,8 +360,6 @@ func New(stack *node.Node, config *ethconfig.Config) (*Ethereum, error) { TxLookupLimit: int64(min(config.TransactionHistory, math.MaxInt64)), VmConfig: vm.Config{ EnablePreimageRecording: config.EnablePreimageRecording, - EnableWitnessStats: config.EnableWitnessStats, - StatelessSelfValidation: config.StatelessSelfValidation, EnableOpcodeOptimizations: config.EnableOpcodeOptimizing, }, // Enables file journaling for the trie database. The journal files will be stored @@ -378,6 +368,9 @@ func New(stack *node.Node, config *ethconfig.Config) (*Ethereum, error) { // - DATADIR/triedb/verkle.journal TrieJournalDirectory: stack.ResolvePath("triedb"), StateSizeTracking: config.EnableStateSizeTracking, + + StatelessSelfValidation: config.StatelessSelfValidation, + EnableWitnessStats: config.EnableWitnessStats, } ) if config.DisableTxIndexer { @@ -471,7 +464,6 @@ func New(stack *node.Node, config *ethconfig.Config) (*Ethereum, error) { RequiredBlocks: config.RequiredBlocks, DirectBroadcast: config.DirectBroadcast, EnableEVNFeatures: stack.Config().EnableEVNFeatures, - EnableBAL: config.EnableBAL, EVNNodeIdsWhitelist: stack.Config().P2P.EVNNodeIdsWhitelist, ProxyedValidatorAddresses: stack.Config().P2P.ProxyedValidatorAddresses, ProxyedNodeIds: stack.Config().P2P.ProxyedNodeIds, diff --git a/eth/catalyst/simulated_beacon.go b/eth/catalyst/simulated_beacon.go index ee87301852..f2264216cf 100644 --- a/eth/catalyst/simulated_beacon.go +++ b/eth/catalyst/simulated_beacon.go @@ -100,7 +100,7 @@ type SimulatedBeacon struct { func payloadVersion(config *params.ChainConfig, time uint64) engine.PayloadVersion { switch config.LatestFork(time) { - case forks.Pasteur, forks.BPO5, forks.BPO4, forks.BPO3, forks.BPO2, forks.BPO1, forks.Mendel, forks.Osaka, + case forks.BPO5, forks.BPO4, forks.BPO3, forks.BPO2, forks.BPO1, forks.Pasteur, forks.Mendel, forks.Osaka, forks.Fermi, forks.Maxwell, forks.Lorentz, forks.Prague, forks.Cancun: return engine.PayloadV3 case forks.Paris, forks.Shanghai: diff --git a/eth/downloader/downloader_test.go b/eth/downloader/downloader_test.go index 7a0dcb4590..158994c689 100644 --- a/eth/downloader/downloader_test.go +++ b/eth/downloader/downloader_test.go @@ -116,6 +116,7 @@ func (dl *downloadTester) newPeer(id string, version uint, blocks []*types.Block id: id, chain: newTestBlockchain(blocks), withholdHeaders: make(map[common.Hash]struct{}), + dropped: make(chan error, 1), } dl.peers[id] = peer @@ -144,6 +145,9 @@ type downloadTesterPeer struct { chain *core.BlockChain withholdHeaders map[common.Hash]struct{} + corruptBodies bool // if set, the peer serves incorrect bodies + + dropped chan error // signaled when res.Done receives an error } func (dlp *downloadTesterPeer) MarkLagging() { @@ -279,6 +283,11 @@ func (dlp *downloadTesterPeer) RequestBodies(hashes []common.Hash, sink chan *et txsHashes[i] = types.DeriveSha(types.Transactions(body.Transactions), hasher) uncleHashes[i] = types.CalcUncleHash(body.Uncles) } + if dlp.corruptBodies { + for i := range txsHashes { + txsHashes[i] = common.Hash{0xff} + } + } req := ð.Request{ Peer: dlp.id, } @@ -291,10 +300,16 @@ func (dlp *downloadTesterPeer) RequestBodies(hashes []common.Hash, sink chan *et WithdrawalRoots: withdrawalHashes, }, Time: 1, - Done: make(chan error, 1), // Ignore the returned status + Done: make(chan error), } go func() { sink <- res + if err := <-res.Done; err != nil { + select { + case dlp.dropped <- err: + default: + } + } }() return req, nil } @@ -1263,3 +1278,21 @@ func TestRemoteHeaderRequestSpan(t *testing.T) { } } } + +// TestInvalidBodyPeerDrop verifies that a peer serving corrupted block bodies +// is signalled through res.Done so the eth protocol handler can drop it. +func TestInvalidBodyPeerDrop(t *testing.T) { + tester := newTester(t) + defer tester.terminate() + + chain := testChainBase.shorten(blockCacheMaxItems - 15) + peer := tester.newPeer("corrupt", eth.ETH68, chain.blocks[1:]) + peer.corruptBodies = true + + go tester.sync("corrupt", nil, FullSync) + select { + case <-peer.dropped: + case <-time.After(1 * time.Minute): + t.Fatal("peer was not dropped") + } +} diff --git a/eth/downloader/fetchers_concurrent.go b/eth/downloader/fetchers_concurrent.go index 2e485d028d..cb0f4ba63d 100644 --- a/eth/downloader/fetchers_concurrent.go +++ b/eth/downloader/fetchers_concurrent.go @@ -357,25 +357,32 @@ func (d *Downloader) concurrentFetch(queue typedQueue, beaconMode bool) error { delete(pending, res.Req.Peer) delete(stales, res.Req.Peer) - // Signal the dispatcher that the round trip is done. We'll drop the - // peer if the data turns out to be junk. - res.Done <- nil - res.Req.Close() - // If the peer was previously banned and failed to deliver its pack // in a reasonable time frame, ignore its message. - if peer := d.peers.Peer(res.Req.Peer); peer != nil { - // Deliver the received chunk of data and check chain validity - accepted, err := queue.deliver(peer, res) - if errors.Is(err, errInvalidChain) { - return err - } - // Unless a peer delivered something completely else than requested (usually - // caused by a timed out request which came through in the end), set it to - // idle. If the delivery's stale, the peer should have already been idled. - if !errors.Is(err, errStaleDelivery) { - queue.updateCapacity(peer, accepted, res.Time) - } + peer := d.peers.Peer(res.Req.Peer) + if peer == nil { + res.Done <- nil + res.Req.Close() + continue + } + // Deliver the received chunk of data and check chain validity + accepted, err := queue.deliver(peer, res) + // Unless a peer delivered something completely else than requested (usually + // caused by a timed out request which came through in the end), set it to + // idle. If the delivery's stale, the peer should have already been idled. + if !errors.Is(err, errStaleDelivery) { + queue.updateCapacity(peer, accepted, res.Time) + } + res.Done <- validityErrorOfRequest(err) + res.Req.Close() + + if errors.Is(err, errInvalidChain) { + // errInvalidChain is the signal that processing of items failed internally, + // even though the items were validly encoded. + // + // This can be due to invalid blocks, or a database error. + // The sync cycle should be aborted for such errors, so we return it here. + return err } case cont := <-queue.waker(): @@ -386,3 +393,11 @@ func (d *Downloader) concurrentFetch(queue typedQueue, beaconMode bool) error { } } } + +// validityErrorOfRequest returns err if it is related to block validity, and nil otherwise. +func validityErrorOfRequest(err error) error { + if errors.Is(err, errInvalidBody) || errors.Is(err, errInvalidReceipt) { + return err + } + return nil +} diff --git a/eth/downloader/queue.go b/eth/downloader/queue.go index 8f2845f240..e9e93dd6fa 100644 --- a/eth/downloader/queue.go +++ b/eth/downloader/queue.go @@ -918,10 +918,10 @@ func (q *queue) deliver(id string, taskPool map[common.Hash]*types.Header, } // Assemble each of the results with their headers and retrieved data parts var ( - accepted int - failure error - i int - hashes []common.Hash + accepted int + failure error + i int + foundStale bool ) for _, header := range request.Headers { // Short circuit assembly if no more fetch results are found @@ -933,42 +933,41 @@ func (q *queue) deliver(id string, taskPool map[common.Hash]*types.Header, failure = err break } - hashes = append(hashes, header.Hash()) i++ } - for _, header := range request.Headers[:i] { + for k, header := range request.Headers[:i] { if res, stale, err := q.resultCache.GetDeliverySlot(header.Number.Uint64()); err == nil && !stale { - reconstruct(accepted, res) + reconstruct(k, res) + accepted++ } else { - // else: between here and above, some other peer filled this result, + // Between here and above, some other peer filled this result, // or it was indeed a no-op. This should not happen, but if it does it's // not something to panic about log.Error("Delivery stale", "stale", stale, "number", header.Number.Uint64(), "err", err) - failure = errStaleDelivery + foundStale = true } // Clean up a successful fetch - delete(taskPool, hashes[accepted]) - accepted++ + delete(taskPool, header.Hash()) } resDropMeter.Mark(int64(results - accepted)) // Return all failed or missing fetches to the queue - for _, header := range request.Headers[accepted:] { + for _, header := range request.Headers[i:] { taskQueue.Push(header, -int64(header.Number.Uint64())) } // Wake up Results if accepted > 0 { q.active.Signal() } - if failure == nil { - return accepted, nil + if failure != nil { + return accepted, failure } // If none of the data was good, it's a stale delivery - if accepted > 0 { - return accepted, fmt.Errorf("partial failure: %v", failure) + if foundStale { + return accepted, errStaleDelivery } - return accepted, fmt.Errorf("%w: %v", failure, errStaleDelivery) + return accepted, nil } // Prepare configures the result cache to allow accepting and caching inbound diff --git a/eth/ethconfig/config.go b/eth/ethconfig/config.go index c34ec2315c..8297e21d55 100644 --- a/eth/ethconfig/config.go +++ b/eth/ethconfig/config.go @@ -117,7 +117,6 @@ type Config struct { NoPruning bool // Whether to disable pruning and flush everything to disk NoPrefetch bool // Whether to disable prefetching and only load state on demand - EnableBAL bool DirectBroadcast bool DisableSnapProtocol bool // Whether disable snap protocol RangeLimit bool @@ -231,15 +230,15 @@ type Config struct { // OverrideMendel (TODO: remove after the fork) OverrideMendel *uint64 `toml:",omitempty"` + // OverridePasteur (TODO: remove after the fork) + OverridePasteur *uint64 `toml:",omitempty"` + // OverrideBPO1 (TODO: remove after the fork) OverrideBPO1 *uint64 `toml:",omitempty"` // OverrideBPO2 (TODO: remove after the fork) OverrideBPO2 *uint64 `toml:",omitempty"` - // OverridePasteur (TODO: remove after the fork) - OverridePasteur *uint64 `toml:",omitempty"` - // OverrideVerkle (TODO: remove after the fork) OverrideVerkle *uint64 `toml:",omitempty"` diff --git a/eth/ethconfig/gen_config.go b/eth/ethconfig/gen_config.go index 613ef4c808..a7e0c4d398 100644 --- a/eth/ethconfig/gen_config.go +++ b/eth/ethconfig/gen_config.go @@ -30,7 +30,6 @@ func (c Config) MarshalTOML() (interface{}, error) { BscDiscoveryURLs []string NoPruning bool NoPrefetch bool - EnableBAL bool DirectBroadcast bool DisableSnapProtocol bool RangeLimit bool @@ -79,9 +78,9 @@ func (c Config) MarshalTOML() (interface{}, error) { OverrideFermi *uint64 `toml:",omitempty"` OverrideOsaka *uint64 `toml:",omitempty"` OverrideMendel *uint64 `toml:",omitempty"` + OverridePasteur *uint64 `toml:",omitempty"` OverrideBPO1 *uint64 `toml:",omitempty"` OverrideBPO2 *uint64 `toml:",omitempty"` - OverridePasteur *uint64 `toml:",omitempty"` OverrideVerkle *uint64 `toml:",omitempty"` TxSyncDefaultTimeout time.Duration `toml:",omitempty"` TxSyncMaxTimeout time.Duration `toml:",omitempty"` @@ -108,7 +107,6 @@ func (c Config) MarshalTOML() (interface{}, error) { enc.BscDiscoveryURLs = c.BscDiscoveryURLs enc.NoPruning = c.NoPruning enc.NoPrefetch = c.NoPrefetch - enc.EnableBAL = c.EnableBAL enc.DirectBroadcast = c.DirectBroadcast enc.DisableSnapProtocol = c.DisableSnapProtocol enc.RangeLimit = c.RangeLimit @@ -157,9 +155,9 @@ func (c Config) MarshalTOML() (interface{}, error) { enc.OverrideFermi = c.OverrideFermi enc.OverrideOsaka = c.OverrideOsaka enc.OverrideMendel = c.OverrideMendel + enc.OverridePasteur = c.OverridePasteur enc.OverrideBPO1 = c.OverrideBPO1 enc.OverrideBPO2 = c.OverrideBPO2 - enc.OverridePasteur = c.OverridePasteur enc.OverrideVerkle = c.OverrideVerkle enc.TxSyncDefaultTimeout = c.TxSyncDefaultTimeout enc.TxSyncMaxTimeout = c.TxSyncMaxTimeout @@ -190,7 +188,6 @@ func (c *Config) UnmarshalTOML(unmarshal func(interface{}) error) error { BscDiscoveryURLs []string NoPruning *bool NoPrefetch *bool - EnableBAL *bool DirectBroadcast *bool DisableSnapProtocol *bool RangeLimit *bool @@ -239,9 +236,9 @@ func (c *Config) UnmarshalTOML(unmarshal func(interface{}) error) error { OverrideFermi *uint64 `toml:",omitempty"` OverrideOsaka *uint64 `toml:",omitempty"` OverrideMendel *uint64 `toml:",omitempty"` + OverridePasteur *uint64 `toml:",omitempty"` OverrideBPO1 *uint64 `toml:",omitempty"` OverrideBPO2 *uint64 `toml:",omitempty"` - OverridePasteur *uint64 `toml:",omitempty"` OverrideVerkle *uint64 `toml:",omitempty"` TxSyncDefaultTimeout *time.Duration `toml:",omitempty"` TxSyncMaxTimeout *time.Duration `toml:",omitempty"` @@ -295,9 +292,6 @@ func (c *Config) UnmarshalTOML(unmarshal func(interface{}) error) error { if dec.NoPrefetch != nil { c.NoPrefetch = *dec.NoPrefetch } - if dec.EnableBAL != nil { - c.EnableBAL = *dec.EnableBAL - } if dec.DirectBroadcast != nil { c.DirectBroadcast = *dec.DirectBroadcast } @@ -442,15 +436,15 @@ func (c *Config) UnmarshalTOML(unmarshal func(interface{}) error) error { if dec.OverrideMendel != nil { c.OverrideMendel = dec.OverrideMendel } + if dec.OverridePasteur != nil { + c.OverridePasteur = dec.OverridePasteur + } if dec.OverrideBPO1 != nil { c.OverrideBPO1 = dec.OverrideBPO1 } if dec.OverrideBPO2 != nil { c.OverrideBPO2 = dec.OverrideBPO2 } - if dec.OverridePasteur != nil { - c.OverridePasteur = dec.OverridePasteur - } if dec.OverrideVerkle != nil { c.OverrideVerkle = dec.OverrideVerkle } diff --git a/eth/fetcher/block_fetcher.go b/eth/fetcher/block_fetcher.go index f157250b1c..d432d64cd3 100644 --- a/eth/fetcher/block_fetcher.go +++ b/eth/fetcher/block_fetcher.go @@ -914,7 +914,7 @@ func (f *BlockFetcher) importBlocks(op *blockOrHeaderInject) { hash := block.Hash() // Run the import on a new thread - log.Debug("Importing propagated block", "peer", peer, "number", block.Number(), "hash", hash, "balSize", block.BALSize()) + log.Debug("Importing propagated block", "peer", peer, "number", block.Number(), "hash", hash) go func() { // If the parent's unknown, abort insertion parent := f.getBlock(block.ParentHash()) diff --git a/eth/filters/api.go b/eth/filters/api.go index 692a018413..b974213dff 100644 --- a/eth/filters/api.go +++ b/eth/filters/api.go @@ -175,11 +175,13 @@ func (api *FilterAPI) NewPendingTransactions(ctx context.Context, fullTx *bool) return &rpc.Subscription{}, rpc.ErrNotificationsUnsupported } - rpcSub := notifier.CreateSubscription() + var ( + rpcSub = notifier.CreateSubscription() + txs = make(chan []*types.Transaction, 128) + pendingTxSub = api.events.SubscribePendingTxs(txs) + ) gopool.Submit(func() { - txs := make(chan []*types.Transaction, 128) - pendingTxSub := api.events.SubscribePendingTxs(txs) defer pendingTxSub.Unsubscribe() chainConfig := api.sys.backend.ChainConfig() @@ -219,6 +221,7 @@ func (api *FilterAPI) NewVotesFilter() rpc.ID { api.filtersMu.Unlock() gopool.Submit(func() { + defer voteSub.Unsubscribe() for { select { case vote := <-votes: @@ -246,18 +249,20 @@ func (api *FilterAPI) NewVotes(ctx context.Context) (*rpc.Subscription, error) { return &rpc.Subscription{}, rpc.ErrNotificationsUnsupported } - rpcSub := notifier.CreateSubscription() + var ( + rpcSub = notifier.CreateSubscription() + votes = make(chan *types.VoteEnvelope, 128) + voteSub = api.events.SubscribeNewVotes(votes) + ) gopool.Submit(func() { - votes := make(chan *types.VoteEnvelope, 128) - voteSub := api.events.SubscribeNewVotes(votes) + defer voteSub.Unsubscribe() for { select { case vote := <-votes: notifier.Notify(rpcSub.ID, vote) case <-rpcSub.Err(): - voteSub.Unsubscribe() return } } @@ -307,11 +312,13 @@ func (api *FilterAPI) NewHeads(ctx context.Context) (*rpc.Subscription, error) { return &rpc.Subscription{}, rpc.ErrNotificationsUnsupported } - rpcSub := notifier.CreateSubscription() + var ( + rpcSub = notifier.CreateSubscription() + headers = make(chan *types.Header) + headersSub = api.events.SubscribeNewHeads(headers) + ) gopool.Submit(func() { - headers := make(chan *types.Header) - headersSub := api.events.SubscribeNewHeads(headers) defer headersSub.Unsubscribe() for { @@ -339,6 +346,7 @@ func (api *FilterAPI) NewFinalizedHeaderFilter() rpc.ID { api.filtersMu.Unlock() gopool.Submit(func() { + defer headerSub.Unsubscribe() for { select { case h := <-headers: @@ -366,18 +374,20 @@ func (api *FilterAPI) NewFinalizedHeaders(ctx context.Context) (*rpc.Subscriptio return &rpc.Subscription{}, rpc.ErrNotificationsUnsupported } - rpcSub := notifier.CreateSubscription() + var ( + rpcSub = notifier.CreateSubscription() + headers = make(chan *types.Header) + headersSub = api.events.SubscribeNewFinalizedHeaders(headers) + ) gopool.Submit(func() { - headers := make(chan *types.Header) - headersSub := api.events.SubscribeNewFinalizedHeaders(headers) + defer headersSub.Unsubscribe() for { select { case h := <-headers: notifier.Notify(rpcSub.ID, h) case <-rpcSub.Err(): - headersSub.Unsubscribe() return } } diff --git a/eth/filters/filter.go b/eth/filters/filter.go index b5b3812e25..f719eb766b 100644 --- a/eth/filters/filter.go +++ b/eth/filters/filter.go @@ -389,7 +389,7 @@ func (f *Filter) rangeLogs(ctx context.Context, firstBlock, lastBlock uint64) ([ } if firstBlock > lastBlock { - return nil, nil + return nil, errInvalidBlockRange } mb := f.sys.backend.NewMatcherBackend() defer mb.Close() diff --git a/eth/filters/filter_test.go b/eth/filters/filter_test.go index 1d67820cb5..1d9014af5f 100644 --- a/eth/filters/filter_test.go +++ b/eth/filters/filter_test.go @@ -360,7 +360,8 @@ func testFilters(t *testing.T, history uint64, noHistory bool) { want: `[{"address":"0xff00000000000000000000000000000000000000","topics":["0x0000000000000000000000000000000000000000000000000000746f70696333"],"data":"0x","blockNumber":"0x3e7","transactionHash":"0x53e3675800c6908424b61b35a44e51ca4c73ca603e58a65b32c67968b4f42200","transactionIndex":"0x0","blockHash":"0x2e4620a2b426b0612ec6cad9603f466723edaed87f98c9137405dd4f7a2409ff","logIndex":"0x0","removed":false}]`, }, { - f: sys.NewRangeFilter(int64(rpc.LatestBlockNumber), int64(rpc.FinalizedBlockNumber), nil, nil), + f: sys.NewRangeFilter(int64(rpc.LatestBlockNumber), int64(rpc.FinalizedBlockNumber), nil, nil, false), + err: errInvalidBlockRange.Error(), }, { f: sys.NewRangeFilter(int64(rpc.SafeBlockNumber), int64(rpc.LatestBlockNumber), nil, nil), diff --git a/eth/handler.go b/eth/handler.go index 83c628b23c..1ea417074f 100644 --- a/eth/handler.go +++ b/eth/handler.go @@ -143,7 +143,6 @@ type handlerConfig struct { PeerSet *peerSet EnableQuickBlockFetching bool EnableEVNFeatures bool - EnableBAL bool EVNNodeIdsWhitelist []enode.ID ProxyedValidatorAddresses []common.Address ProxyedNodeIds []enode.ID @@ -154,7 +153,6 @@ type handler struct { networkID uint64 disablePeerTxBroadcast bool enableEVNFeatures bool - enableBAL bool evnNodeIdsWhitelistMap map[enode.ID]struct{} proxyedValidatorAddressMap map[common.Address]struct{} proxyedNodeIdsMap map[enode.ID]struct{} @@ -228,7 +226,6 @@ func newHandler(config *handlerConfig) (*handler, error) { requiredBlocks: config.RequiredBlocks, directBroadcast: config.DirectBroadcast, enableEVNFeatures: config.EnableEVNFeatures, - enableBAL: config.EnableBAL, evnNodeIdsWhitelistMap: make(map[enode.ID]struct{}), proxyedValidatorAddressMap: make(map[common.Address]struct{}), proxyedNodeIdsMap: make(map[enode.ID]struct{}), @@ -358,7 +355,6 @@ func newHandler(config *handlerConfig) (*handler, error) { for i, item := range res { block := types.NewBlockWithHeader(item.Header).WithBody(types.Body{Transactions: item.Txs, Uncles: item.Uncles}) block = block.WithSidecars(item.Sidecars) - block = block.WithBAL(item.BAL) block.ReceivedAt = time.Now() block.ReceivedFrom = p.ID() if err := block.SanityCheck(); err != nil { @@ -481,10 +477,6 @@ func (h *handler) runEthPeer(peer *eth.Peer, handler eth.Handler) error { peer.Log().Error("Bsc extension barrier failed", "err", err) return err } - if bscExt != nil && bscExt.Version() == bsc.Bsc3 { - peer.CanHandleBAL.Store(true) - log.Debug("runEthPeer", "bscExt.Version", bscExt.Version(), "CanHandleBAL", peer.CanHandleBAL.Load()) - } // Execute the Ethereum handshake var ( head = h.chain.CurrentHeader() @@ -855,7 +847,6 @@ func (h *handler) BroadcastBlock(block *types.Block, propagate bool) { log.Debug("Broadcast block to peer", "hash", hash, "peer", peer.ID(), "EVNPeerFlag", peer.EVNPeerFlag.Load(), - "CanHandleBAL", peer.CanHandleBAL.Load(), ) peer.AsyncSendNewBlock(block, td) } @@ -868,7 +859,6 @@ func (h *handler) BroadcastBlock(block *types.Block, propagate bool) { log.Debug("Broadcast block to proxyed peer", "hash", hash, "peer", peer.ID(), "EVNPeerFlag", peer.EVNPeerFlag.Load(), - "CanHandleBAL", peer.CanHandleBAL.Load(), ) peer.AsyncSendNewBlock(block, td) proxyedPeersCnt++ @@ -884,7 +874,6 @@ func (h *handler) BroadcastBlock(block *types.Block, propagate bool) { log.Debug("Broadcast block to EVN peer", "hash", hash, "peer", peer.ID(), "EVNPeerFlag", peer.EVNPeerFlag.Load(), - "CanHandleBAL", peer.CanHandleBAL.Load(), ) peer.AsyncSendNewBlock(block, td) evnPeersCnt++ @@ -906,7 +895,7 @@ func (h *handler) BroadcastBlock(block *types.Block, propagate bool) { if h.chain.HasBlock(hash, block.NumberU64()) { for _, peer := range peers { log.Debug("Announced block to peer", "hash", hash, "peer", peer.ID(), - "EVNPeerFlag", peer.EVNPeerFlag.Load(), "CanHandleBAL", peer.CanHandleBAL.Load()) + "EVNPeerFlag", peer.EVNPeerFlag.Load()) peer.AsyncSendNewBlockHash(block) } log.Debug("Announced block", "hash", hash, "recipients", len(peers), "duration", common.PrettyDuration(time.Since(block.ReceivedAt))) diff --git a/eth/handler_bsc.go b/eth/handler_bsc.go index 791c60db1e..a5cc01a0f6 100644 --- a/eth/handler_bsc.go +++ b/eth/handler_bsc.go @@ -48,11 +48,9 @@ func (h *bscHandler) Handle(peer *bsc.Peer, packet bsc.Packet) error { } // handleVotesBroadcast is invoked from a peer's message handler when it transmits a -// votes broadcast for the local node to process. +// votes broadcast for the local node to process. Per-peer rate limiting happens +// upstream in bsc.handleVotes via IsOverLimitAfterReceivingVotes. func (h *bscHandler) handleVotesBroadcast(peer *bsc.Peer, votes []*types.VoteEnvelope) error { - if peer.IsOverLimitAfterReceiving() { - return nil - } // Here we only put the first vote, to avoid ddos attack by sending a large batch of votes. // This won't abandon any valid vote, because one vote is sent every time referring to func voteBroadcastLoop if len(votes) > 0 { diff --git a/eth/handler_eth.go b/eth/handler_eth.go index eb3f231be2..d56269f420 100644 --- a/eth/handler_eth.go +++ b/eth/handler_eth.go @@ -171,10 +171,6 @@ func (h *ethHandler) handleBlockBroadcast(peer *eth.Peer, packet *eth.NewBlockPa if sidecars != nil { block = block.WithSidecars(sidecars) } - if packet.Bal != nil && h.chain.Engine().VerifyBAL(block, packet.Bal) == nil { - block = block.WithBAL(packet.Bal) - } - // Schedule the block for import log.Debug("handleBlockBroadcast", "peer", peer.ID(), "block", block.Number(), "hash", block.Hash()) h.blockFetcher.Enqueue(peer.ID(), block) diff --git a/eth/protocols/bsc/handler.go b/eth/protocols/bsc/handler.go index df15894a14..1beaf113e7 100644 --- a/eth/protocols/bsc/handler.go +++ b/eth/protocols/bsc/handler.go @@ -13,9 +13,20 @@ import ( "github.com/ethereum/go-ethereum/p2p" "github.com/ethereum/go-ethereum/p2p/enode" "github.com/ethereum/go-ethereum/p2p/enr" + "github.com/ethereum/go-ethereum/rlp" ) -const MaxRequestRangeBlocksCount = 64 +const ( + // MaxRequestRangeBlocksCount is the maximum number of blocks to serve per + // GetBlocksByRange request. Mostly there to bound disk lookups; with BSC's + // typical block size, the practical limit will always be softResponseLimit. + MaxRequestRangeBlocksCount = 64 + + // softResponseLimit is the target maximum size of replies. The hard cap on + // the wire is maxMessageSize (10MB); 8MB leaves headroom for outer RLP/p2p + // framing. Each entry's measured size includes sidecars. + softResponseLimit = 8 * 1024 * 1024 +) // Handler is a callback to invoke from an outside runner after the boilerplate // exchanges have passed. @@ -150,6 +161,11 @@ func handleVotes(backend Backend, msg Decoder, peer *Peer) error { if err := msg.Decode(ann); err != nil { return fmt.Errorf("%w: message %v: %v", errDecode, msg, err) } + // Charge limiter by vote count, not packet count, to match the documented + // intent of receiveRateLimitPerSecond (see peer.go:23-27). + if peer.IsOverLimitAfterReceivingVotes(uint(len(ann.Votes))) { + return nil + } // Schedule all the unknown hashes for retrieval peer.markVotes(ann.Votes) return backend.Handle(peer, ann) @@ -168,7 +184,7 @@ func handleGetBlocksByRange(backend Backend, msg Decoder, peer *Peer) error { } // Get requested blocks - blocks := make([]*BlockData, 0, req.Count) + blocks := make([]rlp.RawValue, 0, req.Count) var block *types.Block // Prioritize blockHash query, get block & sidecars from db if req.StartBlockHash != (common.Hash{}) { @@ -179,19 +195,28 @@ func handleGetBlocksByRange(backend Backend, msg Decoder, peer *Peer) error { if block == nil { return fmt.Errorf("msg %v, cannot get start block: %v, %v", GetBlocksByRangeMsg, req.StartBlockHeight, req.StartBlockHash) } - blocks = append(blocks, NewBlockData(block)) - balSize := block.BALSize() - for i := uint64(1); i < req.Count; i++ { - block = backend.Chain().GetBlockByHash(block.ParentHash()) - if block == nil { + responseSize := 0 + for i := uint64(0); i < req.Count; i++ { + if i > 0 { + block = backend.Chain().GetBlockByHash(block.ParentHash()) + if block == nil { + break + } + } + enc, err := rlp.EncodeToBytes(NewBlockData(block)) + if err != nil { + log.Error("failed to encode BlockData", "hash", block.Hash(), "err", err) break } - balSize += block.BALSize() - blocks = append(blocks, NewBlockData(block)) + if len(blocks) > 0 && responseSize+len(enc) > softResponseLimit { + break // already have at least one block; next entry would overflow + } + blocks = append(blocks, enc) + responseSize += len(enc) } - log.Debug("reply GetBlocksByRange msg", "from", peer.id, "req", req.Count, "blocks", len(blocks), "balSize", balSize) - return p2p.Send(peer.rw, BlocksByRangeMsg, &BlocksByRangePacket{ + log.Debug("reply GetBlocksByRange msg", "from", peer.id, "req", req.Count, "blocks", len(blocks), "responseSize", responseSize) + return p2p.Send(peer.rw, BlocksByRangeMsg, &BlocksByRangeRLPPacket{ RequestId: req.RequestId, Blocks: blocks, }) diff --git a/eth/protocols/bsc/peer.go b/eth/protocols/bsc/peer.go index c74a956e86..733f5c1e90 100644 --- a/eth/protocols/bsc/peer.go +++ b/eth/protocols/bsc/peer.go @@ -124,9 +124,10 @@ func (p *Peer) AsyncSendVotes(votes []*types.VoteEnvelope) { } } -// Step into the next period when secondsPerPeriod seconds passed, -// Otherwise, check whether the number of received votes extra (secondsPerPeriod * receiveRateLimitPerSecond) -func (p *Peer) IsOverLimitAfterReceiving() bool { +// IsOverLimitAfterReceivingVotes increments the per-period vote counter by n +// and reports whether the rolling 30s budget has been exceeded. +// The budget is `secondsPerPeriod * receiveRateLimitPerSecond` votes per peer. +func (p *Peer) IsOverLimitAfterReceivingVotes(n uint) bool { if timeInterval := time.Since(p.periodBegin).Seconds(); timeInterval >= secondsPerPeriod { if p.periodCounter > uint(secondsPerPeriod*receiveRateLimitPerSecond) { p.Log().Debug("sending votes too much", "secondsPerPeriod", secondsPerPeriod, "count ", p.periodCounter) @@ -135,7 +136,7 @@ func (p *Peer) IsOverLimitAfterReceiving() bool { p.periodCounter = 0 return false } - p.periodCounter += 1 + p.periodCounter += n return p.periodCounter > uint(secondsPerPeriod*receiveRateLimitPerSecond) } diff --git a/eth/protocols/bsc/protocol.go b/eth/protocols/bsc/protocol.go index fc3eb5b709..3f60c3f19a 100644 --- a/eth/protocols/bsc/protocol.go +++ b/eth/protocols/bsc/protocol.go @@ -12,7 +12,6 @@ import ( const ( Bsc1 = 1 Bsc2 = 2 - Bsc3 = 3 // to BAL process ) // ProtocolName is the official short name of the `bsc` protocol used during @@ -21,11 +20,11 @@ const ProtocolName = "bsc" // ProtocolVersions are the supported versions of the `bsc` protocol (first // is primary). -var ProtocolVersions = []uint{Bsc1, Bsc2, Bsc3} +var ProtocolVersions = []uint{Bsc1, Bsc2} // protocolLengths are the number of implemented message corresponding to // different protocol versions. -var protocolLengths = map[uint]uint64{Bsc1: 2, Bsc2: 4, Bsc3: 4} +var protocolLengths = map[uint]uint64{Bsc1: 2, Bsc2: 4} // maxMessageSize is the maximum cap on the size of a protocol message. const maxMessageSize = 10 * 1024 * 1024 @@ -83,9 +82,8 @@ type BlockData struct { Header *types.Header Txs []*types.Transaction Uncles []*types.Header - Withdrawals []*types.Withdrawal `rlp:"optional"` - Sidecars types.BlobSidecars `rlp:"optional"` - BAL *types.BlockAccessListEncode `rlp:"optional"` + Withdrawals []*types.Withdrawal `rlp:"optional"` + Sidecars types.BlobSidecars `rlp:"optional"` } // NewBlockData creates a new BlockData object from a block @@ -96,7 +94,6 @@ func NewBlockData(block *types.Block) *BlockData { Uncles: block.Uncles(), Withdrawals: block.Withdrawals(), Sidecars: block.Sidecars(), - BAL: block.BAL(), } } @@ -107,3 +104,11 @@ type BlocksByRangePacket struct { func (*BlocksByRangePacket) Name() string { return "BlocksByRange" } func (*BlocksByRangePacket) Kind() byte { return BlocksByRangeMsg } + +// BlocksByRangeRLPPacket mirrors BlocksByRangePacket on the wire but carries +// pre-encoded entries, letting the server reuse RLP bytes already produced for +// size accounting and avoid a redundant encode pass in p2p.Send. +type BlocksByRangeRLPPacket struct { + RequestId uint64 + Blocks []rlp.RawValue +} diff --git a/eth/protocols/eth/handler_test.go b/eth/protocols/eth/handler_test.go index 12f4a4b016..b6dbc29872 100644 --- a/eth/protocols/eth/handler_test.go +++ b/eth/protocols/eth/handler_test.go @@ -429,16 +429,20 @@ func testGetBlockBodies(t *testing.T, protocol uint) { {0, []common.Hash{backend.chain.CurrentBlock().Hash()}, []bool{true}, 1}, // The chains head block should be retrievable {0, []common.Hash{{}}, []bool{false}, 0}, // A non existent block should not be returned - // Existing and non-existing blocks interleaved should not cause problems + // Existing blocks followed by a non-existing one should stop at the gap {0, []common.Hash{ - {}, backend.chain.GetBlockByNumber(1).Hash(), - {}, backend.chain.GetBlockByNumber(10).Hash(), - {}, backend.chain.GetBlockByNumber(100).Hash(), {}, - }, []bool{false, true, false, true, false, true, false}, 3}, + }, []bool{true, true, true, false}, 3}, + + // A non-existing block at the start should return nothing + {0, []common.Hash{ + {}, + backend.chain.GetBlockByNumber(1).Hash(), + backend.chain.GetBlockByNumber(10).Hash(), + }, []bool{false, true, true}, 0}, } // Run each of the tests and verify the results against the chain for i, tt := range tests { diff --git a/eth/protocols/eth/handlers.go b/eth/protocols/eth/handlers.go index ca9b142e7f..4ed19a788d 100644 --- a/eth/protocols/eth/handlers.go +++ b/eth/protocols/eth/handlers.go @@ -240,7 +240,7 @@ func ServiceGetBlockBodiesQuery(chain *core.BlockChain, query GetBlockBodiesRequ } body := chain.GetBody(hash) if body == nil { - continue + break // If we don't have this block's body, stop serving. } sidecars := chain.GetSidecarsByHash(hash) bodyWithSidecars := &struct { @@ -257,7 +257,7 @@ func ServiceGetBlockBodiesQuery(chain *core.BlockChain, query GetBlockBodiesRequ enc, err := rlp.EncodeToBytes(bodyWithSidecars) if err != nil { log.Error("block body encode err", "hash", hash, "err", err) - continue + break } bodies = append(bodies, enc) bytes += len(enc) @@ -301,19 +301,20 @@ func ServiceGetReceiptsQuery68(chain *core.BlockChain, query GetReceiptsRequest) // Retrieve the requested block's receipts results := chain.GetReceiptsRLP(hash) if results == nil { + // If we don't have this block (or it isn't an empty-receipts block), stop serving. if header := chain.GetHeaderByHash(hash); header == nil || header.ReceiptHash != types.EmptyRootHash { - continue + break } } else { body := chain.GetBodyRLP(hash) if body == nil { - continue + break // The block body is missing, stop serving. } var err error results, err = blockReceiptsToNetwork68(results, body) if err != nil { log.Error("Error in block receipts conversion", "hash", hash, "err", err) - continue + break } } receipts = append(receipts, results) @@ -338,19 +339,20 @@ func serviceGetReceiptsQuery69(chain *core.BlockChain, query GetReceiptsRequest) // Retrieve the requested block's receipts results := chain.GetReceiptsRLP(hash) if results == nil { + // If we don't have this block (or it isn't an empty-receipts block), stop serving. if header := chain.GetHeaderByHash(hash); header == nil || header.ReceiptHash != types.EmptyRootHash { - continue + break } } else { body := chain.GetBodyRLP(hash) if body == nil { - continue + break // The block body is missing, stop serving. } var err error results, err = blockReceiptsToNetwork69(results, body) if err != nil { log.Error("Error in block receipts conversion", "hash", hash, "err", err) - continue + break } } receipts = append(receipts, results) @@ -380,13 +382,6 @@ func handleNewBlock(backend Backend, msg Decoder, peer *Peer) error { return fmt.Errorf("%w: message %v: %v", errDecode, msg, err) } - if ann.Bal != nil { - log.Debug("handleNewBlock, BAL", "number", ann.Block.NumberU64(), "hash", ann.Block.Hash(), "peer", peer.ID(), - "version", ann.Bal.Version, "signData", len(ann.Bal.SignData), "accounts", len(ann.Bal.Accounts), "balSize", ann.Block.BALSize()) - } else { - log.Debug("handleNewBlock, no BAL", "number", ann.Block.NumberU64(), "hash", ann.Block.Hash(), "peer", peer.ID(), - "txNum", len(ann.Block.Transactions()), "balSize", ann.Block.BALSize()) - } // Now that we have our packet, perform operations using the interface methods if err := ann.sanityCheck(); err != nil { return err diff --git a/eth/protocols/eth/peer.go b/eth/protocols/eth/peer.go index b70806b0de..b172795fcf 100644 --- a/eth/protocols/eth/peer.go +++ b/eth/protocols/eth/peer.go @@ -26,7 +26,6 @@ import ( mapset "github.com/deckarep/golang-set/v2" "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/core/types" - "github.com/ethereum/go-ethereum/log" "github.com/ethereum/go-ethereum/p2p" "github.com/ethereum/go-ethereum/p2p/enode" "github.com/ethereum/go-ethereum/p2p/tracker" @@ -318,23 +317,11 @@ func (p *Peer) AsyncSendNewBlockHash(block *types.Block) { func (p *Peer) SendNewBlock(block *types.Block, td *big.Int) error { // Mark all the block hash as known, but ensure we don't overflow our limits p.knownBlocks.Add(block.Hash()) - bal := block.BAL() - if !p.CanHandleBAL.Load() { - bal = nil - } - if bal != nil { - log.Debug("SendNewBlock", "number", block.NumberU64(), "hash", block.Hash(), "peer", p.ID(), - "balSize", block.BALSize(), "version", bal.Version, "canHandleBAL", p.CanHandleBAL.Load()) - } else { - log.Debug("SendNewBlock no BAL", "number", block.NumberU64(), "hash", block.Hash(), "peer", p.ID(), - "txNum", len(block.Transactions()), "canHandleBAL", p.CanHandleBAL.Load()) - } return p2p.Send(p.rw, NewBlockMsg, &NewBlockPacket{ Block: block, TD: td, Sidecars: block.Sidecars(), - Bal: bal, }) } diff --git a/eth/protocols/eth/protocol.go b/eth/protocols/eth/protocol.go index 84d9428d1f..e9e417d7d1 100644 --- a/eth/protocols/eth/protocol.go +++ b/eth/protocols/eth/protocol.go @@ -238,8 +238,7 @@ type BlockHeadersRLPPacket struct { type NewBlockPacket struct { Block *types.Block TD *big.Int - Sidecars types.BlobSidecars `rlp:"optional"` - Bal *types.BlockAccessListEncode `rlp:"optional"` + Sidecars types.BlobSidecars `rlp:"optional"` } // sanityCheck verifies that the values are reasonable, as a DoS protection diff --git a/eth/protocols/snap/sync.go b/eth/protocols/snap/sync.go index 8263932f2c..5f79003ff6 100644 --- a/eth/protocols/snap/sync.go +++ b/eth/protocols/snap/sync.go @@ -776,7 +776,6 @@ func (s *Syncer) Sync(root common.Hash, cancel chan struct{}) error { func (s *Syncer) loadSyncStatus() { var progress SyncProgress - stateDiskDB := s.db.GetStateStore() if status := rawdb.ReadSnapshotSyncStatus(s.db); status != nil { if err := json.Unmarshal(status, &progress); err != nil { log.Error("Failed to decode snap sync status", "err", err) @@ -795,7 +794,7 @@ func (s *Syncer) loadSyncStatus() { // Allocate batch for account trie generation task.genBatch = ethdb.HookedBatch{ - Batch: stateDiskDB.NewBatch(), + Batch: s.db.NewBatch(), OnPut: func(key []byte, value []byte) { s.accountBytes += common.StorageSize(len(key) + len(value)) }, @@ -810,7 +809,7 @@ func (s *Syncer) loadSyncStatus() { for accountHash, subtasks := range task.SubTasks { for _, subtask := range subtasks { subtask.genBatch = ethdb.HookedBatch{ - Batch: stateDiskDB.NewBatch(), + Batch: s.db.NewBatch(), OnPut: func(key []byte, value []byte) { s.storageBytes += common.StorageSize(len(key) + len(value)) }, @@ -867,7 +866,7 @@ func (s *Syncer) loadSyncStatus() { last = common.MaxHash } batch := ethdb.HookedBatch{ - Batch: stateDiskDB.NewBatch(), + Batch: s.db.NewBatch(), OnPut: func(key []byte, value []byte) { s.accountBytes += common.StorageSize(len(key) + len(value)) }, @@ -1964,7 +1963,7 @@ func (s *Syncer) processAccountResponse(res *accountResponse) { } // Mark the healing tag if storage root node is inconsistent, or // it's non-existent due to storage chunking. - if !rawdb.HasTrieNode(s.db.StateStoreReader(), res.hashes[i], nil, account.Root, s.scheme) { + if !rawdb.HasTrieNode(s.db, res.hashes[i], nil, account.Root, s.scheme) { res.task.needHeal[i] = true } } else { @@ -2079,23 +2078,12 @@ func (s *Syncer) processStorageResponse(res *storageResponse) { res.subTask.req = nil } - var usingMultDatabase bool batch := ethdb.HookedBatch{ - Batch: s.db.GetStateStore().NewBatch(), + Batch: s.db.NewBatch(), OnPut: func(key []byte, value []byte) { s.storageBytes += common.StorageSize(len(key) + len(value)) }, } - var snapBatch ethdb.HookedBatch - if s.db.HasSeparateStateStore() { - usingMultDatabase = true - snapBatch = ethdb.HookedBatch{ - Batch: s.db.NewBatch(), - OnPut: func(key []byte, value []byte) { - s.storageBytes += common.StorageSize(len(key) + len(value)) - }, - } - } var ( slots int @@ -2167,7 +2155,7 @@ func (s *Syncer) processStorageResponse(res *storageResponse) { } // Our first task is the one that was just filled by this response. batch := ethdb.HookedBatch{ - Batch: s.db.GetStateStore().NewBatch(), + Batch: s.db.NewBatch(), OnPut: func(key []byte, value []byte) { s.storageBytes += common.StorageSize(len(key) + len(value)) }, @@ -2189,7 +2177,7 @@ func (s *Syncer) processStorageResponse(res *storageResponse) { }) for r.Next() { batch := ethdb.HookedBatch{ - Batch: s.db.GetStateStore().NewBatch(), + Batch: s.db.NewBatch(), OnPut: func(key []byte, value []byte) { s.storageBytes += common.StorageSize(len(key) + len(value)) }, @@ -2269,11 +2257,7 @@ func (s *Syncer) processStorageResponse(res *storageResponse) { // outdated during the sync, but it can be fixed later during the // snapshot generation. for j := 0; j < len(res.hashes[i]); j++ { - if usingMultDatabase { - rawdb.WriteStorageSnapshot(snapBatch, account, res.hashes[i][j], res.slots[i][j]) - } else { - rawdb.WriteStorageSnapshot(batch, account, res.hashes[i][j], res.slots[i][j]) - } + rawdb.WriteStorageSnapshot(batch, account, res.hashes[i][j], res.slots[i][j]) // If we're storing large contracts, generate the trie nodes // on the fly to not trash the gluing points if i == len(res.hashes)-1 && res.subTask != nil { @@ -2293,7 +2277,7 @@ func (s *Syncer) processStorageResponse(res *storageResponse) { // If the chunk's root is an overflown but full delivery, // clear the heal request. accountHash := res.accounts[len(res.accounts)-1] - if root == res.subTask.root && rawdb.HasTrieNode(s.db.StateStoreReader(), accountHash, nil, root, s.scheme) { + if root == res.subTask.root && rawdb.HasTrieNode(s.db, accountHash, nil, root, s.scheme) { for i, account := range res.mainTask.res.hashes { if account == accountHash { res.mainTask.needHeal[i] = false @@ -2313,11 +2297,6 @@ func (s *Syncer) processStorageResponse(res *storageResponse) { if err := batch.Write(); err != nil { log.Crit("Failed to persist storage slots", "err", err) } - if usingMultDatabase { - if err := snapBatch.Write(); err != nil { - log.Crit("Failed to persist storage slots", "err", err) - } - } s.storageSynced += uint64(slots) log.Debug("Persisted set of storage slots", "accounts", len(res.hashes), "slots", slots, "bytes", s.storageBytes-oldStorageBytes) @@ -2416,25 +2395,13 @@ func (s *Syncer) commitHealer(force bool) { return } batch := s.db.NewBatch() - var stateBatch ethdb.Batch - var err error - if s.db.HasSeparateStateStore() { - stateBatch = s.db.GetStateStore().NewBatch() - err = s.healer.scheduler.Commit(batch, stateBatch) - } else { - err = s.healer.scheduler.Commit(batch, nil) - } + err := s.healer.scheduler.Commit(batch) if err != nil { log.Crit("Failed to commit healing data", "err", err) } if err := batch.Write(); err != nil { log.Crit("Failed to persist healing data", "err", err) } - if s.db.HasSeparateStateStore() { - if err := stateBatch.Write(); err != nil { - log.Crit("Failed to persist healing data", "err", err) - } - } log.Debug("Persisted set of healing data", "type", "trienodes", "bytes", common.StorageSize(batch.ValueSize())) } diff --git a/eth/tracers/api.go b/eth/tracers/api.go index 3efcc83667..9c78866784 100644 --- a/eth/tracers/api.go +++ b/eth/tracers/api.go @@ -1313,6 +1313,10 @@ func overrideConfig(original *params.ChainConfig, override *params.ChainConfig) copy.MendelTime = timestamp canon = false } + if timestamp := override.PasteurTime; timestamp != nil { + copy.PasteurTime = timestamp + canon = false + } if timestamp := override.BPO1Time; timestamp != nil { copy.BPO1Time = timestamp canon = false @@ -1321,10 +1325,6 @@ func overrideConfig(original *params.ChainConfig, override *params.ChainConfig) copy.BPO2Time = timestamp canon = false } - if timestamp := override.PasteurTime; timestamp != nil { - copy.PasteurTime = timestamp - canon = false - } if timestamp := override.VerkleTime; timestamp != nil { copy.VerkleTime = timestamp canon = false diff --git a/eth/tracers/logger/access_list_tracer.go b/eth/tracers/logger/access_list_tracer.go index 0d51f40522..e629eb3d31 100644 --- a/eth/tracers/logger/access_list_tracer.go +++ b/eth/tracers/logger/access_list_tracer.go @@ -106,9 +106,10 @@ type AccessListTracer struct { func NewAccessListTracer(acl types.AccessList, addressesToExclude map[common.Address]struct{}) *AccessListTracer { list := newAccessList() for _, al := range acl { - if _, ok := addressesToExclude[al.Address]; !ok { - list.addAddress(al.Address) + if _, ok := addressesToExclude[al.Address]; ok { + continue } + list.addAddress(al.Address) for _, slot := range al.StorageKeys { list.addSlot(al.Address, slot) } diff --git a/eth/tracers/logger/access_list_tracer_test.go b/eth/tracers/logger/access_list_tracer_test.go new file mode 100644 index 0000000000..04b2b4b31b --- /dev/null +++ b/eth/tracers/logger/access_list_tracer_test.go @@ -0,0 +1,39 @@ +// Copyright 2026 The go-ethereum Authors +// This file is part of the go-ethereum library. +// +// The go-ethereum library is free software: you can redistribute it and/or modify +// it under the terms of the GNU Lesser General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// The go-ethereum library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public License +// along with the go-ethereum library. If not, see . + +package logger + +import ( + "testing" + + "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/core/types" +) + +func TestNewAccessListTracerExcludedAddress(t *testing.T) { + excluded := common.HexToAddress("0x2222222222222222222222222222222222222222") + slot := common.HexToHash("0x01") + prelude := types.AccessList{{ + Address: excluded, + StorageKeys: []common.Hash{slot}, + }} + excl := map[common.Address]struct{}{excluded: {}} + tracer := NewAccessListTracer(prelude, excl) + got := tracer.AccessList() + if len(got) != 0 { + t.Fatalf("excluded prelude address must not contribute tuples, got %+v", got) + } +} diff --git a/eth/tracers/native/mux.go b/eth/tracers/native/mux.go index 4da3e2531d..c6c5ebbca3 100644 --- a/eth/tracers/native/mux.go +++ b/eth/tracers/native/mux.go @@ -71,6 +71,8 @@ func newMuxTracer(ctx *tracers.Context, cfg json.RawMessage, chainConfig *params OnStorageChange: t.OnStorageChange, OnLog: t.OnLog, OnSystemTxFixIntrinsicGas: t.OnSystemTxFixIntrinsicGas, + OnSystemCallStartV2: t.OnSystemCallStart, + OnSystemCallEnd: t.OnSystemCallEnd, }, GetResult: t.GetResult, Stop: t.Stop, @@ -181,6 +183,24 @@ func (t *muxTracer) OnSystemTxFixIntrinsicGas(intrinsicGas uint64) { } } +func (t *muxTracer) OnSystemCallStart(vm *tracing.VMContext) { + for _, t := range t.tracers { + if t.OnSystemCallStartV2 != nil { + t.OnSystemCallStartV2(vm) + } else if t.OnSystemCallStart != nil { + t.OnSystemCallStart() + } + } +} + +func (t *muxTracer) OnSystemCallEnd() { + for _, t := range t.tracers { + if t.OnSystemCallEnd != nil { + t.OnSystemCallEnd() + } + } +} + // GetResult returns an empty json object. func (t *muxTracer) GetResult() (json.RawMessage, error) { resObject := make(map[string]json.RawMessage) diff --git a/ethclient/ethclient.go b/ethclient/ethclient.go index 06536ee451..1b2c30f527 100644 --- a/ethclient/ethclient.go +++ b/ethclient/ethclient.go @@ -29,6 +29,7 @@ import ( "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/common/hexutil" "github.com/ethereum/go-ethereum/core/types" + buildertypes "github.com/ethereum/go-ethereum/core/types/builder" "github.com/ethereum/go-ethereum/rpc" ) @@ -861,7 +862,7 @@ func (ec *Client) HasBuilder(ctx context.Context, address common.Address) (bool, } // SendBid sends a bid -func (ec *Client) SendBid(ctx context.Context, args types.BidArgs) (common.Hash, error) { +func (ec *Client) SendBid(ctx context.Context, args buildertypes.BidArgs) (common.Hash, error) { var hash common.Hash err := ec.c.CallContext(ctx, &hash, "mev_sendBid", args) if err != nil { @@ -870,6 +871,36 @@ func (ec *Client) SendBid(ctx context.Context, args types.BidArgs) (common.Hash, return hash, nil } +// SendBidBlock sends a BidBlock (zero-simulate MEV path). +func (ec *Client) SendBidBlock(ctx context.Context, args buildertypes.BidBlockArgs) (common.Hash, error) { + var hash common.Hash + err := ec.c.CallContext(ctx, &hash, "mev_sendBidBlock", args) + if err != nil { + return common.Hash{}, err + } + return hash, nil +} + +// BidBlockPermission is the result of mev_getBidBlockPermission. +type BidBlockPermission struct { + Allowed bool `json:"allowed"` + Reason string `json:"reason,omitempty"` + BlockHash *common.Hash `json:"blockHash,omitempty"` + BlockNumber *hexutil.Uint64 `json:"blockNumber,omitempty"` + RevokedAt *time.Time `json:"revokedAt,omitempty"` + ResetAt time.Time `json:"resetAt"` +} + +// GetBidBlockPermission queries the builder's current BidBlock permission status. +func (ec *Client) GetBidBlockPermission(ctx context.Context, builder common.Address) (*BidBlockPermission, error) { + var result BidBlockPermission + err := ec.c.CallContext(ctx, &result, "mev_getBidBlockPermission", builder) + if err != nil { + return nil, err + } + return &result, nil +} + // BestBidGasFee returns the gas fee of the best bid for the given parent hash. func (ec *Client) BestBidGasFee(ctx context.Context, parentHash common.Hash) (*big.Int, error) { var fee *big.Int @@ -881,8 +912,8 @@ func (ec *Client) BestBidGasFee(ctx context.Context, parentHash common.Hash) (*b } // MevParams returns the static params of mev -func (ec *Client) MevParams(ctx context.Context) (*types.MevParams, error) { - var params types.MevParams +func (ec *Client) MevParams(ctx context.Context) (*buildertypes.MevParams, error) { + var params buildertypes.MevParams err := ec.c.CallContext(ctx, ¶ms, "mev_params") if err != nil { return nil, err diff --git a/ethdb/database.go b/ethdb/database.go index 53bca2693c..d0aa1f3a8b 100644 --- a/ethdb/database.go +++ b/ethdb/database.go @@ -215,17 +215,11 @@ type AncientStater interface { AncientDatadir() (string, error) } -// StateStoreReader wraps the StateStoreReader method. -type StateStoreReader interface { - StateStoreReader() Reader -} - // Reader contains the methods required to read data from both key-value as well as // immutable ancient data. type Reader interface { KeyValueReader AncientReader - StateStoreReader } // AncientStore contains all the methods required to allow handling different @@ -237,12 +231,6 @@ type AncientStore interface { io.Closer } -type StateStore interface { - SetStateStore(state Database) - GetStateStore() Database - HasSeparateStateStore() bool -} - // ResettableAncientStore extends the AncientStore interface by adding a Reset method. type ResettableAncientStore interface { AncientStore @@ -254,8 +242,6 @@ type ResettableAncientStore interface { // Database contains all the methods required by the high level database to not // only access the key-value data store but also the ancient chain store. type Database interface { - StateStore - StateStoreReader AncientFreezer KeyValueStore diff --git a/ethdb/memorydb/memorydb.go b/ethdb/memorydb/memorydb.go index e69540f95e..6d9eb92ed4 100644 --- a/ethdb/memorydb/memorydb.go +++ b/ethdb/memorydb/memorydb.go @@ -44,8 +44,6 @@ var ( type Database struct { db map[string][]byte lock sync.RWMutex - - stateStore ethdb.Database } func (db *Database) ModifyAncients(f func(ethdb.AncientWriteOp) error) (int64, error) { @@ -290,13 +288,6 @@ func (db *Database) Len() int { return len(db.db) } -func (db *Database) StateStoreReader() ethdb.Reader { - if db.stateStore == nil { - return db - } - return db.stateStore -} - // keyvalue is a key-value tuple tagged with a deletion field to allow creating // memory-database write batches. type keyvalue struct { diff --git a/ethdb/remotedb/remotedb.go b/ethdb/remotedb/remotedb.go index 83018c1fa4..9e0e5e9de4 100644 --- a/ethdb/remotedb/remotedb.go +++ b/ethdb/remotedb/remotedb.go @@ -75,22 +75,6 @@ func (db *Database) AncientSize(kind string) (uint64, error) { panic("not supported") } -func (db *Database) SetStateStore(state ethdb.Database) { - panic("not supported") -} - -func (db *Database) GetStateStore() ethdb.Database { - panic("not supported") -} - -func (db *Database) HasSeparateStateStore() bool { - panic("not supported") -} - -func (db *Database) StateStoreReader() ethdb.Reader { - return db -} - func (db *Database) ReadAncients(fn func(op ethdb.AncientReaderOp) error) (err error) { return fn(db) } diff --git a/go.mod b/go.mod index d39346b320..42b193e8a7 100644 --- a/go.mod +++ b/go.mod @@ -40,7 +40,6 @@ require ( github.com/google/gofuzz v1.2.0 github.com/google/pprof v0.0.0-20241210010833-40e02aabc2ad github.com/google/uuid v1.6.0 - github.com/gorilla/mux v1.8.1 github.com/gorilla/websocket v1.5.3 github.com/graph-gophers/graphql-go v1.3.0 github.com/hashicorp/go-bexpr v0.1.10 @@ -91,7 +90,6 @@ require ( google.golang.org/protobuf v1.36.11 gopkg.in/natefinch/lumberjack.v2 v2.2.1 gopkg.in/yaml.v3 v3.0.1 - gotest.tools v2.2.0+incompatible ) require ( diff --git a/go.sum b/go.sum index d623e52d0d..1234ce693a 100644 --- a/go.sum +++ b/go.sum @@ -513,8 +513,6 @@ github.com/gorilla/context v1.1.1/go.mod h1:kBGZzfjB9CEq2AlWe17Uuf7NDRt0dE0s8S51 github.com/gorilla/mux v1.6.2/go.mod h1:1lud6UwP+6orDFRuTfBEV8e9/aOM/c4fVVCaMa2zaAs= github.com/gorilla/mux v1.7.3/go.mod h1:1lud6UwP+6orDFRuTfBEV8e9/aOM/c4fVVCaMa2zaAs= github.com/gorilla/mux v1.8.0/go.mod h1:DVbg23sWSpFRCP0SfiEN6jmj59UnW/n46BH5rLB71So= -github.com/gorilla/mux v1.8.1 h1:TuBL49tXwgrFYWhqrNgrUNEY92u81SPhu7sTdzQEiWY= -github.com/gorilla/mux v1.8.1/go.mod h1:AKf9I4AEqPTmMytcMc0KkNouC66V3BtZ4qD5fmWSiMQ= github.com/gorilla/websocket v0.0.0-20170926233335-4201258b820c/go.mod h1:E7qHFY5m1UJ88s3WnNqhKjPHQ0heANvMoAMk2YaljkQ= github.com/gorilla/websocket v1.5.3 h1:saDtZ6Pbx/0u+bgYQ3q96pZgCzfhKXGPqt7kZ72aNNg= github.com/gorilla/websocket v1.5.3/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE= @@ -1742,8 +1740,6 @@ gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= -gotest.tools v2.2.0+incompatible h1:VsBPFP1AI068pPrMxtb/S8Zkgf9xEmTLJjfM+P5UIEo= -gotest.tools v2.2.0+incompatible/go.mod h1:DsYFclhRJ6vuDpmuTbkuFWG+y2sxOXAzmJt81HFBacw= grpc.go4.org v0.0.0-20170609214715-11d0a25b4919/go.mod h1:77eQGdRu53HpSqPFJFmuJdjuHRquDANNeA4x7B8WQ9o= honnef.co/go/tools v0.0.0-20180728063816-88497007e858/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= diff --git a/internal/ethapi/api.go b/internal/ethapi/api.go index 52ddcce568..0bab97d092 100644 --- a/internal/ethapi/api.go +++ b/internal/ethapi/api.go @@ -42,6 +42,7 @@ import ( "github.com/ethereum/go-ethereum/core/state" "github.com/ethereum/go-ethereum/core/tracing" "github.com/ethereum/go-ethereum/core/types" + buildertypes "github.com/ethereum/go-ethereum/core/types/builder" "github.com/ethereum/go-ethereum/core/vm" "github.com/ethereum/go-ethereum/crypto" "github.com/ethereum/go-ethereum/eth/gasestimator" @@ -62,6 +63,10 @@ const UnHealthyTimeout = 5 * time.Second // allowed to produce in order to speed up calculations. const estimateGasErrorRatio = 0.015 +// maxGetProofKeys is the maximum number of storage keys that can be +// requested in a single eth_getProof call. +const maxGetProofKeys = 1024 + var errBlobTxNotSupported = errors.New("signing blob transactions not supported") var errSubClosed = errors.New("chain subscription closed") @@ -374,6 +379,9 @@ func (n *proofList) Delete(key []byte) error { // GetProof returns the Merkle-proof for a given account and optionally some storage keys. func (api *BlockChainAPI) GetProof(ctx context.Context, address common.Address, storageKeys []string, blockNrOrHash rpc.BlockNumberOrHash) (*AccountResult, error) { + if len(storageKeys) > maxGetProofKeys { + return nil, &invalidParamsError{fmt.Sprintf("too many storage keys requested (max %d, got %d)", maxGetProofKeys, len(storageKeys))} + } var ( keys = make([]common.Hash, len(storageKeys)) keyLengths = make([]int, len(storageKeys)) @@ -406,6 +414,9 @@ func (api *BlockChainAPI) GetProof(ctx context.Context, address common.Address, } // Create the proofs for the storageKeys. for i, key := range keys { + if err := ctx.Err(); err != nil { + return nil, err + } // Output key encoding is a bit special: if the input was a 32-byte hash, it is // returned as such. Otherwise, we apply the QUANTITY encoding mandated by the // JSON-RPC spec for getProof. This behavior exists to preserve backwards @@ -529,6 +540,49 @@ func (api *BlockChainAPI) GetBlockByHash(ctx context.Context, hash common.Hash, return nil, err } +// BlockMevInfo describes a block's MEV builder attribution. +// Version "v1" means legacy SendBid; version "v2" means BEP-675 SendBidBlock. +// Local-mined blocks omit Builder and Version. +type BlockMevInfo struct { + BlockNumber hexutil.Uint64 `json:"blockNumber"` + BlockHash common.Hash `json:"blockHash"` + Miner common.Address `json:"miner"` + Version string `json:"version,omitempty"` + Builder *common.Address `json:"builder,omitempty"` +} + +// GetBlockMevInfo returns the MEV builder attribution for the given block. +func (api *BlockChainAPI) GetBlockMevInfo(ctx context.Context, blockNrOrHash rpc.BlockNumberOrHash) (*BlockMevInfo, error) { + header, err := api.b.HeaderByNumberOrHash(ctx, blockNrOrHash) + if err != nil { + return nil, err + } + if header == nil { + return nil, errors.New("block not found") + } + info := &BlockMevInfo{ + BlockNumber: hexutil.Uint64(header.Number.Uint64()), + BlockHash: header.Hash(), + Miner: header.Coinbase, + } + if header.RequestsHash == nil { + return info, nil + } + version, builder, ok := buildertypes.DecodeBlockMevInfo(*header.RequestsHash) + if !ok { + return info, nil + } + switch version { + case buildertypes.BlockMevInfoVersionBid: + info.Version = "v1" + case buildertypes.BlockMevInfoVersionBidBlock: + info.Version = "v2" + } + b := builder + info.Builder = &b + return info, nil +} + func (api *BlockChainAPI) Health() bool { if rpc.RpcServingTimer != nil { return rpc.RpcServingTimer.Snapshot().Percentile(0.75) < float64(UnHealthyTimeout) @@ -1143,6 +1197,16 @@ func (api *BlockChainAPI) SimulateV1(ctx context.Context, opts simOpts, blockNrO } else if len(opts.BlockStateCalls) > maxSimulateBlocks { return nil, &clientLimitExceededError{message: "too many blocks"} } + var totalCalls int + for _, block := range opts.BlockStateCalls { + if len(block.Calls) > maxSimulateCallsPerBlock { + return nil, &clientLimitExceededError{message: fmt.Sprintf("too many calls in block: %d > %d", len(block.Calls), maxSimulateCallsPerBlock)} + } + totalCalls += len(block.Calls) + if totalCalls > maxSimulateTotalCalls { + return nil, &clientLimitExceededError{message: fmt.Sprintf("too many calls: %d > %d", totalCalls, maxSimulateTotalCalls)} + } + } if blockNrOrHash == nil { n := rpc.BlockNumberOrHashWithNumber(rpc.LatestBlockNumber) blockNrOrHash = &n @@ -1151,17 +1215,12 @@ func (api *BlockChainAPI) SimulateV1(ctx context.Context, opts simOpts, blockNrO if state == nil || err != nil { return nil, err } - gasCap := api.b.RPCGasCap() - if gasCap == 0 { - gasCap = gomath.MaxUint64 - } sim := &simulator{ - b: api.b, - state: state, - base: base, - chainConfig: api.b.ChainConfig(), - // Each tx and all the series of txes shouldn't consume more gas than cap - gp: new(core.GasPool).AddGas(gasCap), + b: api.b, + state: state, + base: base, + chainConfig: api.b.ChainConfig(), + budget: newGasBudget(api.b.RPCGasCap()), traceTransfers: opts.TraceTransfers, validate: opts.Validation, fullTx: opts.ReturnFullTransactions, diff --git a/internal/ethapi/api_mev.go b/internal/ethapi/api_mev.go index c002571c4b..b67e32ac01 100644 --- a/internal/ethapi/api_mev.go +++ b/internal/ethapi/api_mev.go @@ -6,7 +6,8 @@ import ( "time" "github.com/ethereum/go-ethereum/common" - "github.com/ethereum/go-ethereum/core/types" + "github.com/ethereum/go-ethereum/common/hexutil" + buildertypes "github.com/ethereum/go-ethereum/core/types/builder" "github.com/ethereum/go-ethereum/params" ) @@ -24,10 +25,10 @@ func NewMevAPI(b Backend) *MevAPI { // SendBid receives bid from the builders. // If mev is not running or bid is invalid, return error. // Otherwise, creates a builder bid for the given argument, submit it to the miner. -func (m *MevAPI) SendBid(ctx context.Context, args types.BidArgs) (common.Hash, error) { +func (m *MevAPI) SendBid(ctx context.Context, args buildertypes.BidArgs) (common.Hash, error) { ctx = context.WithValue(ctx, "receiveTime", time.Now().UnixMilli()) if !m.b.MevRunning() { - return common.Hash{}, types.ErrMevNotRunning + return common.Hash{}, buildertypes.ErrMevNotRunning } var ( @@ -36,12 +37,12 @@ func (m *MevAPI) SendBid(ctx context.Context, args types.BidArgs) (common.Hash, ) if rawBid == nil { - return common.Hash{}, types.NewInvalidBidError("rawBid should not be nil") + return common.Hash{}, buildertypes.NewInvalidBidError("rawBid should not be nil") } // only support bidding for the next block not for the future block if latestBlockNumber := currentBlock.Number.Uint64(); rawBid.BlockNumber < latestBlockNumber+1 { - return common.Hash{}, types.NewInvalidBidError( + return common.Hash{}, buildertypes.NewInvalidBidError( fmt.Sprintf("stale block number: %d, latest block: %d", rawBid.BlockNumber, latestBlockNumber)) } else if rawBid.BlockNumber > latestBlockNumber+1 { // For the first block of a validator's turn, the previous block must be imported first. @@ -49,45 +50,92 @@ func (m *MevAPI) SendBid(ctx context.Context, args types.BidArgs) (common.Hash, // However, this is not a significant issue because: // a. Each turn consists of 16 blocks, so this situation can only occur at most 1/16 of the time. // b. Each builder is allowed to submit multiple bids for each block. - return common.Hash{}, types.NewInvalidBidError( + return common.Hash{}, buildertypes.NewInvalidBidError( fmt.Sprintf("block in future: %d, latest block: %d", rawBid.BlockNumber, latestBlockNumber)) } else if !m.b.MinerInTurn() { - return common.Hash{}, types.ErrMevNotInTurn + return common.Hash{}, buildertypes.ErrMevNotInTurn } if rawBid.ParentHash != currentBlock.Hash() { - return common.Hash{}, types.NewInvalidBidError( + return common.Hash{}, buildertypes.NewInvalidBidError( fmt.Sprintf("non-aligned parent hash: %v", currentBlock.Hash())) } if rawBid.GasFee == nil || rawBid.GasFee.Cmp(common.Big0) == 0 || rawBid.GasUsed == 0 { - return common.Hash{}, types.NewInvalidBidError("empty gasFee or empty gasUsed") + return common.Hash{}, buildertypes.NewInvalidBidError("empty gasFee or empty gasUsed") } if rawBid.BuilderFee != nil { builderFee := rawBid.BuilderFee if builderFee.Cmp(common.Big0) < 0 { - return common.Hash{}, types.NewInvalidBidError("builder fee should not be less than 0") + return common.Hash{}, buildertypes.NewInvalidBidError("builder fee should not be less than 0") } if builderFee.Cmp(rawBid.GasFee) >= 0 { - return common.Hash{}, types.NewInvalidBidError("builder fee must be less than gas fee") + return common.Hash{}, buildertypes.NewInvalidBidError("builder fee must be less than gas fee") } } if len(args.PayBidTx) == 0 || args.PayBidTxGasUsed == 0 { - return common.Hash{}, types.NewInvalidPayBidTxError("payBidTx and payBidTxGasUsed are must-have") + return common.Hash{}, buildertypes.NewInvalidPayBidTxError("payBidTx and payBidTxGasUsed are must-have") } if args.PayBidTxGasUsed > params.PayBidTxGasLimit { - return common.Hash{}, types.NewInvalidBidError( + return common.Hash{}, buildertypes.NewInvalidBidError( fmt.Sprintf("transfer tx gas used must be no more than %v", params.PayBidTxGasLimit)) } return m.b.SendBid(ctx, &args) } -func (m *MevAPI) Params() *types.MevParams { +// SendBidBlock receives a BidBlock from builders. +func (m *MevAPI) SendBidBlock(ctx context.Context, args buildertypes.BidBlockArgs) (common.Hash, error) { + ctx = context.WithValue(ctx, "receiveTime", time.Now().UnixMilli()) + if !m.b.MevRunning() { + return common.Hash{}, buildertypes.ErrMevNotRunning + } + + // Basic structural validation. + if args.BidBlock == nil { + return common.Hash{}, buildertypes.NewInvalidBidError("empty BidBlock") + } + bb := args.BidBlock + if bb.Header == nil { + return common.Hash{}, buildertypes.NewInvalidBidError("empty Header") + } + + blockNumber := bb.Header.Number.Uint64() + parentHash := bb.Header.ParentHash + currentBlock := m.b.CurrentBlock() + currentNumber := currentBlock.Number.Uint64() + + if blockNumber < currentNumber+1 { + return common.Hash{}, buildertypes.NewInvalidBidError( + fmt.Sprintf("stale block number: %d, latest block: %d", blockNumber, currentNumber)) + } else if blockNumber > currentNumber+1 { + return common.Hash{}, buildertypes.NewInvalidBidError( + fmt.Sprintf("block in future: %d, latest block: %d", blockNumber, currentNumber)) + } else if !m.b.MinerInTurn() { + return common.Hash{}, buildertypes.ErrMevNotInTurn + } + + if parentHash != currentBlock.Hash() { + return common.Hash{}, buildertypes.NewInvalidBidError( + fmt.Sprintf("non-aligned parent hash: %v", currentBlock.Hash())) + } + + if bb.Header.GasUsed == 0 { + return common.Hash{}, buildertypes.NewInvalidBidError("empty gasUsed in header") + } + + if len(bb.Transactions) == 0 { + return common.Hash{}, buildertypes.NewInvalidBidError("empty transactions") + } + + return m.b.SendBidBlock(ctx, &args) +} + +func (m *MevAPI) Params() *buildertypes.MevParams { return m.b.MevParams() } @@ -95,6 +143,34 @@ func (m *MevAPI) HasBuilder(builder common.Address) bool { return m.b.HasBuilder(builder) } +type BidBlockPermissionResult struct { + Allowed bool `json:"allowed"` + Reason string `json:"reason,omitempty"` + BlockHash *common.Hash `json:"blockHash,omitempty"` + BlockNumber *hexutil.Uint64 `json:"blockNumber,omitempty"` + RevokedAt *time.Time `json:"revokedAt,omitempty"` + ResetAt *time.Time `json:"resetAt,omitempty"` +} + +func (m *MevAPI) GetBidBlockPermission(builder common.Address) *BidBlockPermissionResult { + status := m.b.GetBidBlockPermission(builder) + result := &BidBlockPermissionResult{ + Allowed: status.Allowed, + } + if !status.Allowed { + blockHash := status.BlockHash + blockNum := hexutil.Uint64(status.BlockNum) + revokedAt := status.RevokedAt + resetAt := status.ResetAt + result.Reason = status.Reason + result.BlockHash = &blockHash + result.BlockNumber = &blockNum + result.RevokedAt = &revokedAt + result.ResetAt = &resetAt + } + return result +} + // Running returns true if mev is running func (m *MevAPI) Running() bool { return m.b.MevRunning() diff --git a/internal/ethapi/api_test.go b/internal/ethapi/api_test.go index 4163de350c..0d8be8bee8 100644 --- a/internal/ethapi/api_test.go +++ b/internal/ethapi/api_test.go @@ -25,7 +25,6 @@ import ( "errors" "fmt" "maps" - "math" "math/big" "os" "path/filepath" @@ -49,6 +48,7 @@ import ( "github.com/ethereum/go-ethereum/core/rawdb" "github.com/ethereum/go-ethereum/core/state" "github.com/ethereum/go-ethereum/core/types" + buildertypes "github.com/ethereum/go-ethereum/core/types/builder" "github.com/ethereum/go-ethereum/core/vm" "github.com/ethereum/go-ethereum/crypto" "github.com/ethereum/go-ethereum/crypto/kzg4844" @@ -99,6 +99,43 @@ func testTransactionMarshal(t *testing.T, tests []txData, config *params.ChainCo } } +func TestMevAPIGetBidBlockPermission(t *testing.T) { + builder := common.HexToAddress("0x1") + blockHash := common.HexToHash("0xabc") + revokedAt := time.Date(2026, 5, 9, 10, 0, 0, 0, time.UTC) + resetAt := time.Date(2026, 5, 10, 0, 0, 0, 0, time.UTC) + api := NewMevAPI(&testBackend{ + bidBlockPermission: buildertypes.BidBlockPermissionStatus{ + Allowed: false, + Reason: "gasfee_overclaim", + BlockHash: blockHash, + BlockNum: 100, + RevokedAt: revokedAt, + ResetAt: resetAt, + }, + }) + + result := api.GetBidBlockPermission(builder) + if result.Allowed { + t.Fatal("permission should be revoked") + } + if result.Reason != "gasfee_overclaim" { + t.Fatalf("reason: got %s", result.Reason) + } + if result.BlockHash == nil || *result.BlockHash != blockHash { + t.Fatalf("blockHash: got %v, want %s", result.BlockHash, blockHash) + } + if result.BlockNumber == nil || *result.BlockNumber != hexutil.Uint64(100) { + t.Fatalf("blockNumber: got %v, want 100", result.BlockNumber) + } + if result.RevokedAt == nil || !result.RevokedAt.Equal(revokedAt) { + t.Fatalf("revokedAt: got %v, want %s", result.RevokedAt, revokedAt) + } + if !result.ResetAt.Equal(resetAt) { + t.Fatalf("resetAt: got %s, want %s", result.ResetAt, resetAt) + } +} + func TestTransaction_RoundTripRpcJSON(t *testing.T) { t.Parallel() @@ -451,6 +488,8 @@ type testBackend struct { syncDefaultTimeout time.Duration syncMaxTimeout time.Duration + + bidBlockPermission buildertypes.BidBlockPermissionStatus } func fakeBlockHash(txh common.Hash) common.Hash { @@ -722,14 +761,20 @@ func (b testBackend) SubscribeLogsEvent(ch chan<- []*types.Log) event.Subscripti func (b *testBackend) MevRunning() bool { return false } func (b *testBackend) HasBuilder(builder common.Address) bool { return false } -func (b *testBackend) MevParams() *types.MevParams { - return &types.MevParams{} +func (b *testBackend) GetBidBlockPermission(builder common.Address) buildertypes.BidBlockPermissionStatus { + return b.bidBlockPermission +} +func (b *testBackend) MevParams() *buildertypes.MevParams { + return &buildertypes.MevParams{} } func (b *testBackend) StartMev() {} func (b *testBackend) StopMev() {} func (b *testBackend) AddBuilder(builder common.Address, builderUrl string) error { return nil } func (b *testBackend) RemoveBuilder(builder common.Address) error { return nil } -func (b *testBackend) SendBid(ctx context.Context, bid *types.BidArgs) (common.Hash, error) { +func (b *testBackend) SendBid(ctx context.Context, bid *buildertypes.BidArgs) (common.Hash, error) { + panic("implement me") +} +func (b *testBackend) SendBidBlock(ctx context.Context, args *buildertypes.BidBlockArgs) (common.Hash, error) { panic("implement me") } func (b *testBackend) MinerInTurn() bool { return false } @@ -2544,7 +2589,7 @@ func TestSimulateV1ChainLinkage(t *testing.T) { state: stateDB, base: baseHeader, chainConfig: backend.ChainConfig(), - gp: new(core.GasPool).AddGas(math.MaxUint64), + budget: newGasBudget(0), traceTransfers: false, validate: false, fullTx: false, @@ -2629,7 +2674,7 @@ func TestSimulateV1TxSender(t *testing.T) { state: stateDB, base: baseHeader, chainConfig: backend.ChainConfig(), - gp: new(core.GasPool).AddGas(math.MaxUint64), + budget: newGasBudget(0), traceTransfers: false, validate: false, fullTx: true, diff --git a/internal/ethapi/backend.go b/internal/ethapi/backend.go index 5f9429faea..5b9a9624a8 100644 --- a/internal/ethapi/backend.go +++ b/internal/ethapi/backend.go @@ -30,6 +30,7 @@ import ( "github.com/ethereum/go-ethereum/core/filtermaps" "github.com/ethereum/go-ethereum/core/state" "github.com/ethereum/go-ethereum/core/types" + buildertypes "github.com/ethereum/go-ethereum/core/types/builder" "github.com/ethereum/go-ethereum/core/vm" "github.com/ethereum/go-ethereum/ethdb" "github.com/ethereum/go-ethereum/event" @@ -110,7 +111,7 @@ type Backend interface { // MevRunning return true if mev is running MevRunning() bool // MevParams returns the static params of mev - MevParams() *types.MevParams + MevParams() *buildertypes.MevParams // StartMev starts mev StartMev() // StopMev stops mev @@ -121,8 +122,12 @@ type Backend interface { RemoveBuilder(builder common.Address) error // HasBuilder returns true if the builder is in the builder list. HasBuilder(builder common.Address) bool + // GetBidBlockPermission returns the builder's current SendBidBlock permission. + GetBidBlockPermission(builder common.Address) buildertypes.BidBlockPermissionStatus // SendBid receives bid from the builders. - SendBid(ctx context.Context, bid *types.BidArgs) (common.Hash, error) + SendBid(ctx context.Context, bid *buildertypes.BidArgs) (common.Hash, error) + // SendBidBlock receives a BidBlock from builders. + SendBidBlock(ctx context.Context, args *buildertypes.BidBlockArgs) (common.Hash, error) // MinerInTurn returns true if the validator is in turn to propose the block. MinerInTurn() bool diff --git a/internal/ethapi/errors.go b/internal/ethapi/errors.go index 9908ca38c2..22baf39a19 100644 --- a/internal/ethapi/errors.go +++ b/internal/ethapi/errors.go @@ -146,7 +146,7 @@ func txValidationError(err error) *invalidTxError { return &invalidTxError{Message: err.Error(), Code: errCodeIntrinsicGas} case errors.Is(err, core.ErrInsufficientFundsForTransfer): return &invalidTxError{Message: err.Error(), Code: errCodeInsufficientFunds} - case errors.Is(err, core.ErrMaxInitCodeSizeExceeded): + case errors.Is(err, vm.ErrMaxInitCodeSizeExceeded): return &invalidTxError{Message: err.Error(), Code: errCodeMaxInitCodeSizeExceeded} } return &invalidTxError{ diff --git a/internal/ethapi/simulate.go b/internal/ethapi/simulate.go index 377ca33cab..e7dabada59 100644 --- a/internal/ethapi/simulate.go +++ b/internal/ethapi/simulate.go @@ -21,6 +21,7 @@ import ( "encoding/json" "errors" "fmt" + "math" "math/big" "time" @@ -44,6 +45,14 @@ const ( // in a single request. maxSimulateBlocks = 256 + // maxSimulateCallsPerBlock is the maximum number of calls allowed in a + // single simulated block. + maxSimulateCallsPerBlock = 5000 + + // maxSimulateTotalCalls is the maximum total number of calls allowed + // across all simulated blocks in a single request. + maxSimulateTotalCalls = 10000 + // timestampIncrement is the default increment between block timestamps. timestampIncrement = 12 ) @@ -168,6 +177,39 @@ func (m *simChainHeadReader) GetVerifiedBlockByHash(hash common.Hash) *types.Hea return m.Backend.Chain().GetVerifiedBlockByHash(hash) } +// gasBudget tracks the remaining gas allowed across all simulated blocks. +// It enforces the RPC-level gas cap to prevent DoS. +type gasBudget struct { + remaining uint64 +} + +// newGasBudget creates a gas budget with the given cap. +// A cap of 0 is treated as unlimited. +func newGasBudget(cap uint64) *gasBudget { + if cap == 0 { + cap = math.MaxUint64 + } + return &gasBudget{remaining: cap} +} + +// cap returns the given gas value clamped to the remaining budget. +func (b *gasBudget) cap(gas uint64) uint64 { + if gas > b.remaining { + return b.remaining + } + return gas +} + +// consume deducts the given amount from the budget. +// Returns an error if the amount exceeds the remaining budget. +func (b *gasBudget) consume(amount uint64) error { + if amount > b.remaining { + return fmt.Errorf("RPC gas cap exhausted: need %d, remaining %d", amount, b.remaining) + } + b.remaining -= amount + return nil +} + // simulator is a stateful object that simulates a series of blocks. // it is not safe for concurrent use. type simulator struct { @@ -175,7 +217,7 @@ type simulator struct { state *state.StateDB base *types.Header chainConfig *params.ChainConfig - gp *core.GasPool + budget *gasBudget traceTransfers bool validate bool fullTx bool @@ -261,6 +303,7 @@ func (sim *simulator) processBlock(ctx context.Context, block *simBlock, header, } var ( gasUsed, blobGasUsed uint64 + gp = new(core.GasPool).AddGas(blockContext.GasLimit) txes = make([]*types.Transaction, len(block.Calls)) callResults = make([]simCallResult, len(block.Calls)) receipts = make([]*types.Receipt, len(block.Calls)) @@ -309,7 +352,7 @@ func (sim *simulator) processBlock(ctx context.Context, block *simBlock, header, sim.state.SetTxContext(txHash, i) // EoA check is always skipped, even in validation mode. msg := call.ToMessage(header.BaseFee, !sim.validate) - result, err := applyMessageWithEVM(ctx, evm, msg, timeout, sim.gp) + result, err := applyMessageWithEVM(ctx, evm, msg, timeout, gp) if err != nil { txErr := txValidationError(err) return nil, nil, nil, txErr @@ -324,6 +367,13 @@ func (sim *simulator) processBlock(ctx context.Context, block *simBlock, header, gasUsed += result.UsedGas receipts[i] = core.MakeReceipt(evm, result, sim.state, blockContext.BlockNumber, common.Hash{}, blockContext.Time, tx, gasUsed, root) blobGasUsed += receipts[i].BlobGasUsed + + // Make sure the gas cap is still enforced. It's only for + // internally protection. + if err := sim.budget.consume(result.UsedGas); err != nil { + return nil, nil, nil, err + } + logs := tracer.Logs() callRes := simCallResult{ReturnValue: result.Return(), Logs: logs, GasUsed: hexutil.Uint64(result.UsedGas)} if result.Failed() { @@ -400,10 +450,11 @@ func (sim *simulator) sanitizeCall(call *TransactionArgs, state vm.StateDB, head if *gasUsed+uint64(*call.Gas) > blockContext.GasLimit { return &blockGasLimitReachedError{fmt.Sprintf("block gas limit reached: %d >= %d", gasUsed, blockContext.GasLimit)} } - if err := call.CallDefaults(sim.gp.Gas(), header.BaseFee, sim.chainConfig.ChainID); err != nil { - return err - } - return nil + // Clamp to the cross-block gas budget. + gas := sim.budget.cap(uint64(*call.Gas)) + call.Gas = (*hexutil.Uint64)(&gas) + + return call.CallDefaults(0, header.BaseFee, sim.chainConfig.ChainID) } func (sim *simulator) activePrecompiles(base *types.Header) vm.PrecompiledContracts { diff --git a/internal/ethapi/simulate_test.go b/internal/ethapi/simulate_test.go index c747b76477..6a83e744de 100644 --- a/internal/ethapi/simulate_test.go +++ b/internal/ethapi/simulate_test.go @@ -80,7 +80,10 @@ func TestSimulateSanitizeBlockOrder(t *testing.T) { err: "block timestamps must be in order: 72 <= 72", }, } { - sim := &simulator{base: &types.Header{Number: big.NewInt(int64(tc.baseNumber)), Time: tc.baseTimestamp}} + sim := &simulator{ + base: &types.Header{Number: big.NewInt(int64(tc.baseNumber)), Time: tc.baseTimestamp}, + budget: newGasBudget(0), + } res, err := sim.sanitizeChain(tc.blocks) if err != nil { if err.Error() == tc.err { diff --git a/internal/ethapi/transaction_args_test.go b/internal/ethapi/transaction_args_test.go index 39e7d328a8..9a29323565 100644 --- a/internal/ethapi/transaction_args_test.go +++ b/internal/ethapi/transaction_args_test.go @@ -33,6 +33,7 @@ import ( "github.com/ethereum/go-ethereum/core/filtermaps" "github.com/ethereum/go-ethereum/core/state" "github.com/ethereum/go-ethereum/core/types" + buildertypes "github.com/ethereum/go-ethereum/core/types/builder" "github.com/ethereum/go-ethereum/core/vm" "github.com/ethereum/go-ethereum/ethdb" "github.com/ethereum/go-ethereum/event" @@ -423,14 +424,20 @@ func (b *backendMock) CurrentValidators() ([]common.Address, error) { return []c func (b *backendMock) MevRunning() bool { return false } func (b *backendMock) HasBuilder(builder common.Address) bool { return false } -func (b *backendMock) MevParams() *types.MevParams { - return &types.MevParams{} +func (b *backendMock) GetBidBlockPermission(builder common.Address) buildertypes.BidBlockPermissionStatus { + return buildertypes.BidBlockPermissionStatus{} +} +func (b *backendMock) MevParams() *buildertypes.MevParams { + return &buildertypes.MevParams{} } func (b *backendMock) StartMev() {} func (b *backendMock) StopMev() {} func (b *backendMock) AddBuilder(builder common.Address, builderUrl string) error { return nil } func (b *backendMock) RemoveBuilder(builder common.Address) error { return nil } -func (b *backendMock) SendBid(ctx context.Context, bid *types.BidArgs) (common.Hash, error) { +func (b *backendMock) SendBid(ctx context.Context, bid *buildertypes.BidArgs) (common.Hash, error) { + panic("implement me") +} +func (b *backendMock) SendBidBlock(ctx context.Context, args *buildertypes.BidBlockArgs) (common.Hash, error) { panic("implement me") } func (b *backendMock) MinerInTurn() bool { return false } diff --git a/internal/web3ext/web3ext.go b/internal/web3ext/web3ext.go index 8a889b5ffb..cc37bcb1f6 100644 --- a/internal/web3ext/web3ext.go +++ b/internal/web3ext/web3ext.go @@ -144,6 +144,12 @@ web3._extend({ name: 'stopWS', call: 'admin_stopWS' }), + new web3._extend.Method({ + name: 'setBidBlockPermission', + call: 'admin_setBidBlockPermission', + params: 2, + inputFormatter: [web3._extend.formatters.inputAddressFormatter, null] + }), ], properties: [ new web3._extend.Property({ @@ -413,11 +419,6 @@ web3._extend({ params: 2, inputFormatter:[null, null], }), - new web3._extend.Method({ - name: 'freezeClient', - call: 'debug_freezeClient', - params: 1, - }), new web3._extend.Method({ name: 'getAccessibleState', call: 'debug_getAccessibleState', @@ -460,6 +461,12 @@ web3._extend({ params: 1, inputFormatter: [null], }), + new web3._extend.Method({ + name: 'executionWitness', + call: 'debug_executionWitness', + params: 1, + inputFormatter: [null], + }), ], properties: [] }); @@ -672,12 +679,6 @@ web3._extend({ params: 1, inputFormatter: [web3._extend.utils.fromDecimal] }), - new web3._extend.Method({ - name: 'setGasLimit', - call: 'miner_setGasLimit', - params: 1, - inputFormatter: [web3._extend.utils.fromDecimal] - }), new web3._extend.Method({ name: 'setRecommitInterval', call: 'miner_setRecommitInterval', diff --git a/miner/bid_block.go b/miner/bid_block.go new file mode 100644 index 0000000000..5639a7a81c --- /dev/null +++ b/miner/bid_block.go @@ -0,0 +1,327 @@ +// Copyright 2026 The go-ethereum Authors +// This file is part of the go-ethereum library. +// +// BidBlock worker helpers for BEP-675. + +package miner + +import ( + "errors" + "fmt" + "math/big" + "sync" + "time" + + "github.com/holiman/uint256" + + "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/consensus/parlia" + "github.com/ethereum/go-ethereum/core" + "github.com/ethereum/go-ethereum/core/txpool" + "github.com/ethereum/go-ethereum/core/types" + buildertypes "github.com/ethereum/go-ethereum/core/types/builder" + "github.com/ethereum/go-ethereum/log" + "github.com/ethereum/go-ethereum/trie" +) + +type bidBlockTaskInfo struct { + builder common.Address + bidHash common.Hash + gasFee *big.Int + systemTxStart int +} + +var errInvalidBidBlockBlobTx = errors.New("BidBlock blob validation failed") + +// setBidMevInfo tags header.RequestsHash with the BEP-675 block-source info +func setBidMevInfo(header *types.Header, builder common.Address, isBidBlock bool) { + // Legacy BID: a nil RequestsHash denotes a pre-Prague block that must stay + // untagged. BIDBLOCK is post-Prague and validator-owned, so always stamped. + if !isBidBlock && header.RequestsHash == nil { + return + } + version := buildertypes.BlockMevInfoVersionBid + if isBidBlock { + version = buildertypes.BlockMevInfoVersionBidBlock + } + tag := buildertypes.EncodeBlockMevInfo(version, builder) + header.RequestsHash = &tag +} + +func (w *worker) selectBidBlock(bidBlock *buildertypes.DecodedBidBlock, simBidBlockReward, simBidValidatorReward, bestReward *uint256.Int) bool { + if bidBlock == nil { + return false + } + + bidBlockFee := bidBlock.GasFee + bidBlockValidatorReward := new(big.Int).Mul(bidBlockFee, new(big.Int).SetUint64(*w.config.Mev.ValidatorCommission)) + bidBlockValidatorReward.Div(bidBlockValidatorReward, big.NewInt(10000)) + + if simBidValidatorReward != nil && bidBlockValidatorReward.Cmp(simBidValidatorReward.ToBig()) <= 0 { + return false + } + if simBidBlockReward != nil && bidBlockFee.Cmp(simBidBlockReward.ToBig()) <= 0 { + return false + } + + simBidBR := "" + if simBidBlockReward != nil { + simBidBR = simBidBlockReward.String() + } + simBidVR := "" + if simBidValidatorReward != nil { + simBidVR = simBidValidatorReward.String() + } + blockNum := bidBlock.Header.Number.Uint64() + // TODO: switch back to Debug after BidBlock rollout stabilizes. + log.Info("BidSimulator: BidBlock win bid, compare with local", + "block", blockNum, + "bidHash", bidBlock.Hash(), + "localBlockReward", bestReward.String(), + "bidReward", bidBlockFee.String(), + "bidValidatorReward", bidBlockValidatorReward.String(), + "simBidBlockReward", simBidBR, + "simBidValidatorReward", simBidVR) + + if bidBlockFee.Cmp(bestReward.ToBig()) > 0 { + log.Info("[BID BLOCK selected]", + "block", blockNum, + "bidHash", bidBlock.Hash(), + "builder", bidBlock.Builder, + "gasFee", weiToEtherStringF6(bidBlock.GasFee), + "txs", len(bidBlock.Txs)) + return true + } + return false +} + +// bindSignBidBlockSystemTxs signs the verified unsigned system txs from a BidBlock in place. +func bindSignBidBlockSystemTxs( + systemTxs []*types.Transaction, + chainID *big.Int, + p *parlia.Parlia, +) error { + for i, tx := range systemTxs { + signed, err := p.SignSystemTx(tx, chainID) + if err != nil { + return fmt.Errorf("failed to sign system tx %d: %v", i, err) + } + systemTxs[i] = signed + } + return nil +} + +// prepareBidBlockTask signs system txs and assembles a BidBlock task. +// Extra was finalized by the validator during admission (SendBidBlock calls +// SetExtraData before preSealVerifyBidBlock); engine.Seal will later fill the +// reserved vote-attestation/seal-signature bytes. Here we only recompute TxHash +// after bind-signing the trailing system txs. Do not touch fields that enter +// the EVM BlockContext (GasLimit, Coinbase, Time, Difficulty, BaseFee, ...) — +// changing them after the builder's pre-execution would diverge the re-executed +// stateRoot and fail InsertChain. +func (w *worker) prepareBidBlockTask( + decoded *buildertypes.DecodedBidBlock, + start time.Time, +) (*task, error) { + prepareStart := time.Now() + defer bidBlockPrepareTimer.UpdateSince(prepareStart) + + if !w.isRunning() { + return nil, errors.New("worker is not running") + } + + p := w.engine.(*parlia.Parlia) + + // Copy the tx slice so bind-signing does not mutate the cached BidBlock. + allTxs := make([]*types.Transaction, len(decoded.Txs)) + copy(allTxs, decoded.Txs) + + header := types.CopyHeader(decoded.Header) + if err := validateBidBlockBlobTxs(header, allTxs, decoded.Sidecars, decoded.SystemTxStart); err != nil { + if errors.Is(err, errInvalidBidBlockBlobTx) { + w.revokeBidBlockBuilder(decoded.Builder, err.Error(), decoded.Hash(), decoded.BlockNumber()) + } + return nil, err + } + if err := bindSignBidBlockSystemTxs(allTxs[decoded.SystemTxStart:], w.chainConfig.ChainID, p); err != nil { + return nil, err + } + header.TxHash = types.DeriveSha(types.Transactions(allTxs), trie.NewStackTrie(nil)) + + body := &types.Body{ + Transactions: allTxs, + Withdrawals: make([]*types.Withdrawal, 0), + } + block := types.NewBlockWithHeader(header).WithBody(*body).WithSidecars(decoded.Sidecars) + + return &task{ + block: block, + bidBlockInfo: &bidBlockTaskInfo{ + builder: decoded.Builder, + bidHash: decoded.Hash(), + gasFee: decoded.GasFee, + systemTxStart: decoded.SystemTxStart, + }, + createdAt: time.Now(), + miningStartAt: start, + }, nil +} + +type bidBlockBlobValidationJob struct { + txIndex int + tx *types.Transaction +} + +// validateBidBlockBlobTxs runs expensive blob proof checks for the selected BidBlock. +func validateBidBlockBlobTxs(header *types.Header, txs []*types.Transaction, sidecars types.BlobSidecars, systemTxStart int) error { + jobs := make([]bidBlockBlobValidationJob, 0, len(sidecars)) + sidecarIndex := 0 + for txIndex, tx := range txs[:systemTxStart] { + if tx.Type() != types.BlobTxType { + continue + } + sidecar := sidecars[sidecarIndex] + jobs = append(jobs, bidBlockBlobValidationJob{ + txIndex: txIndex, + tx: tx.WithBlobTxSidecar(&sidecar.BlobTxSidecar), + }) + sidecarIndex++ + } + + workers := len(jobs) + if workers > maxBlobValConcurrency { + workers = maxBlobValConcurrency + } + jobCh := make(chan bidBlockBlobValidationJob, len(jobs)) + for _, job := range jobs { + jobCh <- job + } + close(jobCh) + + errCh := make(chan error, len(jobs)) + var wg sync.WaitGroup + wg.Add(workers) + for i := 0; i < workers; i++ { + go func() { + defer wg.Done() + for job := range jobCh { + if err := txpool.ValidateBlobTx(job.tx, header, nil); err != nil { + errCh <- fmt.Errorf("%w: %v", errInvalidBidBlockBlobTx, err) + } + } + }() + } + wg.Wait() + close(errCh) + for err := range errCh { + return err + } + return nil +} + +func (w *worker) enqueueBidBlockTask(task *task, systemTxs int) { + // assembleVoteAttestation + sign header happen inside Seal. + select { + case w.taskCh <- task: + log.Info("[BID BLOCK COMMIT]", + "number", task.block.Number(), + "bidHash", task.bidBlockInfo.bidHash, + "builder", task.bidBlockInfo.builder, + "txs", len(task.block.Transactions()), + "systemTxs", systemTxs, + "gas", task.block.GasUsed(), + "gasFee", weiToEtherStringF6(task.bidBlockInfo.gasFee)) + case <-w.exitCh: + log.Info("Worker has exited") + } +} + +func (w *worker) revokeBidBlockBuilder(builder common.Address, reason string, hash common.Hash, blockNum uint64) { + w.revokeBidBlockBuilderFor(builder, reason, hash, blockNum, bidBlockRevokeDuration) +} + +func (w *worker) revokeBidBlockBuilderFor(builder common.Address, reason string, hash common.Hash, blockNum uint64, duration time.Duration) { + w.permMgr.RevokeFor(builder, reason, hash, blockNum, duration) + bidBlockRevokeGauge.Inc(1) + bidBlockRevokedBuildersGauge.Update(int64(w.permMgr.ActiveRevokeCount())) +} + +// handleBidBlockResult handles a sealed BidBlock: broadcast, then InsertChain for verification. +func (w *worker) handleBidBlockResult(block *types.Block, task *task) { + hash := block.Hash() + + // Broadcast the block first (before verification) + stats := w.chain.GetBlockStats(hash) + stats.SendBlockTime.Store(time.Now().UnixMilli()) + stats.StartMiningTime.Store(task.miningStartAt.UnixMilli()) + + log.Info("[BID BLOCK SEALED]", + "number", block.Number(), + "hash", hash, + "bidHash", task.bidBlockInfo.bidHash, + "builder", task.bidBlockInfo.builder, + "elapsed", common.PrettyDuration(time.Since(task.createdAt))) + + w.mux.Post(core.NewSealedBlockEvent{Block: block}) + + // InsertChain re-executes all txs and validates fields the validator could + // not check at admission. Any mismatch is treated as builder dishonesty and + // revokes the builder for the default lockout window. Categories caught here: + // - Root (post-execution state root) + // - ReceiptHash (post-execution receipts trie root) + // - Bloom (post-execution logs bloom) + // - GasUsed (cumulative gas consumed) + // - Tx precheck failures (nonce, balance, signature, intrinsic gas, ...) + // - System tx value / params (e.g. deposit value vs. SystemAddress balance) + // - Blob sidecar checks (KZG proofs, blob hashes) + verifyStart := time.Now() + _, insertErr := w.chain.InsertChain(types.Blocks{block}) + bidBlockVerifyTimer.UpdateSince(verifyStart) + if insertErr != nil { + log.Error("[BID BLOCK VERIFY FAILED]", + "number", block.Number(), + "hash", hash, + "bidHash", task.bidBlockInfo.bidHash, + "parentHash", block.ParentHash(), + "txs", len(block.Transactions()), + "gasUsed", block.GasUsed(), + "stateRoot", block.Root(), + "receiptHash", block.ReceiptHash(), + "builder", task.bidBlockInfo.builder, + "err", insertErr) + bidBlockVerifyFailedGauge.Inc(1) + w.revokeBidBlockBuilder(task.bidBlockInfo.builder, fmt.Sprintf("InsertChain err: %v", insertErr), hash, block.NumberU64()) + return + } + // Check the post-import average gas price excluding system transactions; only future BidBlock permission is revoked. + if receipts := w.chain.GetReceiptsByHash(block.Hash()); receipts != nil { + avgGasPrice, nonSystemGasUsed, err := validateBidBlockAverageGasPrice( + task.bidBlockInfo.gasFee, + receipts, + task.bidBlockInfo.systemTxStart, + w.config.GasPrice, + ) + if err != nil { + log.Error("[BID BLOCK GASPRICE LOW]", + "number", block.Number(), + "hash", block.Hash(), + "bidHash", task.bidBlockInfo.bidHash, + "builder", task.bidBlockInfo.builder, + "avgGasPrice", avgGasPrice, + "minGasPrice", w.config.GasPrice, + "nonSystemGasUsed", nonSystemGasUsed, + "nonSystemTxs", task.bidBlockInfo.systemTxStart, + "revokeDuration", bidBlockGasPriceLowRevokeDuration, + "err", err) + w.revokeBidBlockBuilderFor(task.bidBlockInfo.builder, err.Error(), block.Hash(), block.NumberU64(), bidBlockGasPriceLowRevokeDuration) + return + } + } + + log.Info("[BID BLOCK VERIFIED]", + "number", block.Number(), + "hash", hash, + "bidHash", task.bidBlockInfo.bidHash, + "builder", task.bidBlockInfo.builder, + "gasFee", weiToEtherStringF6(task.bidBlockInfo.gasFee)) +} diff --git a/miner/bid_block_permission.go b/miner/bid_block_permission.go new file mode 100644 index 0000000000..d454956d76 --- /dev/null +++ b/miner/bid_block_permission.go @@ -0,0 +1,153 @@ +// Copyright 2026 The go-ethereum Authors +// This file is part of the go-ethereum library. +// +// BidBlock permission management (BEP-675 Layer 2). + +package miner + +import ( + "sync" + "time" + + "github.com/ethereum/go-ethereum/common" + buildertypes "github.com/ethereum/go-ethereum/core/types/builder" +) + +// RevokeReasonManual is the Reason value used when an operator manually revokes +// a builder via SetAllowed. Automatic revokes carry the underlying error or +// policy message as Reason directly. +const RevokeReasonManual = "manual" + +const ( + // bidBlockRevokeDuration is the default lockout window for invalid BidBlocks. + bidBlockRevokeDuration = 24 * time.Hour + // bidBlockGasPriceLowRevokeDuration is one epoch for gas-price policy revokes. + bidBlockGasPriceLowRevokeDuration = 450 * time.Second +) + +// BidBlockRevokeRecord holds one active revoke event. +type BidBlockRevokeRecord struct { + RevokedAt time.Time + Duration time.Duration + Reason string // err detail for auto revokes (InsertChain failure), or RevokeReasonManual + BlockHash common.Hash + BlockNum uint64 +} + +// BidBlockPermissionManager tracks per-builder SendBidBlock revokes. +// Revokes are kept in memory and expire lazily after their lockout window. +type BidBlockPermissionManager struct { + mu sync.RWMutex + revoked map[common.Address]BidBlockRevokeRecord + + clock func() time.Time +} + +// NewBidBlockPermissionManager returns a fresh manager with no builders revoked. +func NewBidBlockPermissionManager() *BidBlockPermissionManager { + return &BidBlockPermissionManager{ + revoked: make(map[common.Address]BidBlockRevokeRecord), + clock: time.Now, + } +} + +// IsAllowed reports whether builder may currently use SendBidBlock. +func (m *BidBlockPermissionManager) IsAllowed(builder common.Address) bool { + m.mu.RLock() + defer m.mu.RUnlock() + _, found := m.activeRecord(builder, m.clock()) + return !found +} + +// Revoke denies builder and records the reason exposed by the permission RPC. +func (m *BidBlockPermissionManager) Revoke( + builder common.Address, + reason string, + blockHash common.Hash, + blockNum uint64, +) { + m.RevokeFor(builder, reason, blockHash, blockNum, bidBlockRevokeDuration) +} + +// RevokeFor denies builder for the supplied duration and records the reason +// exposed by the permission RPC. +func (m *BidBlockPermissionManager) RevokeFor( + builder common.Address, + reason string, + blockHash common.Hash, + blockNum uint64, + duration time.Duration, +) { + if duration <= 0 { + duration = bidBlockRevokeDuration + } + m.mu.Lock() + defer m.mu.Unlock() + m.revoked[builder] = BidBlockRevokeRecord{ + RevokedAt: m.clock(), + Duration: duration, + Reason: reason, + BlockHash: blockHash, + BlockNum: blockNum, + } +} + +func (m *BidBlockPermissionManager) GetStatus(builder common.Address) buildertypes.BidBlockPermissionStatus { + m.mu.RLock() + defer m.mu.RUnlock() + status := buildertypes.BidBlockPermissionStatus{ + Allowed: true, + } + rec, found := m.activeRecord(builder, m.clock()) + if !found { + return status + } + status.Allowed = false + status.Reason = rec.Reason + status.BlockHash = rec.BlockHash + status.BlockNum = rec.BlockNum + status.RevokedAt = rec.RevokedAt + status.ResetAt = rec.RevokedAt.Add(rec.Duration) + return status +} + +// ActiveRevokeCount returns the number of currently revoked builders. +func (m *BidBlockPermissionManager) ActiveRevokeCount() int { + m.mu.RLock() + defer m.mu.RUnlock() + now := m.clock() + count := 0 + for _, rec := range m.revoked { + if isRevokeActive(rec, now) { + count++ + } + } + return count +} + +func (m *BidBlockPermissionManager) SetAllowed(builder common.Address, allowed bool) { + m.mu.Lock() + defer m.mu.Unlock() + if allowed { + delete(m.revoked, builder) + return + } + m.revoked[builder] = BidBlockRevokeRecord{ + RevokedAt: m.clock(), + Duration: bidBlockRevokeDuration, + Reason: RevokeReasonManual, + } +} + +// isRevokeActive reports whether now is before the revoke reset time. +func isRevokeActive(rec BidBlockRevokeRecord, now time.Time) bool { + return now.Before(rec.RevokedAt.Add(rec.Duration)) +} + +func (m *BidBlockPermissionManager) activeRecord(builder common.Address, now time.Time) (BidBlockRevokeRecord, bool) { + rec, found := m.revoked[builder] + if !found || !isRevokeActive(rec, now) { + return BidBlockRevokeRecord{}, false + } + return rec, true +} diff --git a/miner/bid_block_permission_test.go b/miner/bid_block_permission_test.go new file mode 100644 index 0000000000..92519c2ada --- /dev/null +++ b/miner/bid_block_permission_test.go @@ -0,0 +1,413 @@ +// Copyright 2026 The go-ethereum Authors +// This file is part of the go-ethereum library. + +package miner + +import ( + "context" + "strings" + "sync" + "testing" + "time" + + "github.com/ethereum/go-ethereum/common" + buildertypes "github.com/ethereum/go-ethereum/core/types/builder" + "github.com/ethereum/go-ethereum/miner/builderclient" + "github.com/ethereum/go-ethereum/miner/minerconfig" +) + +// testInsertChainReason is a placeholder used by tests where the specific +// InsertChain error text doesn't matter — production passes +// "InsertChain err: " here. +const testInsertChainReason = "InsertChain err: test" + +func getBidBlockPermissionRecord(m *BidBlockPermissionManager, builder common.Address) (BidBlockRevokeRecord, bool) { + m.mu.RLock() + defer m.mu.RUnlock() + return m.activeRecord(builder, m.clock()) +} + +func setBidBlockPermissionClock(m *BidBlockPermissionManager, f func() time.Time) { + m.mu.Lock() + defer m.mu.Unlock() + m.clock = f +} + +func TestBidBlockPermission_DefaultActive(t *testing.T) { + m := NewBidBlockPermissionManager() + builder := common.HexToAddress("0x1") + if !m.IsAllowed(builder) { + t.Fatal("default state should be Active for any builder") + } + if _, ok := getBidBlockPermissionRecord(m, builder); ok { + t.Fatal("no record expected for fresh builder") + } +} + +func TestBidBlockPermission_RevokeBlocks(t *testing.T) { + m := NewBidBlockPermissionManager() + builder := common.HexToAddress("0x1") + hash := common.HexToHash("0xabc") + + m.Revoke(builder, testInsertChainReason, hash, 100) + if m.IsAllowed(builder) { + t.Fatal("revoked builder should not be allowed within 24h of revoke") + } + + rec, ok := getBidBlockPermissionRecord(m, builder) + if !ok { + t.Fatal("record expected after Revoke") + } + if rec.Reason != testInsertChainReason { + t.Fatalf("reason: got %s, want %s", rec.Reason, testInsertChainReason) + } + if rec.BlockHash != hash { + t.Fatalf("blockHash: got %s, want %s", rec.BlockHash.Hex(), hash.Hex()) + } + if rec.BlockNum != 100 { + t.Fatalf("blockNum: got %d, want 100", rec.BlockNum) + } + if rec.Duration != bidBlockRevokeDuration { + t.Fatalf("duration: got %s, want %s", rec.Duration, bidBlockRevokeDuration) + } +} + +func TestBidBlockPermission_BuildersIndependent(t *testing.T) { + m := NewBidBlockPermissionManager() + a := common.HexToAddress("0xa") + b := common.HexToAddress("0xb") + + m.Revoke(a, testInsertChainReason, common.Hash{}, 1) + if m.IsAllowed(a) { + t.Fatal("a should be revoked") + } + if !m.IsAllowed(b) { + t.Fatal("b should remain active") + } +} + +func TestBidBlockPermission_RevokeForCustomDuration(t *testing.T) { + m := NewBidBlockPermissionManager() + builder := common.HexToAddress("0x1") + now := time.Date(2026, 5, 8, 12, 0, 0, 0, time.UTC) + + setBidBlockPermissionClock(m, func() time.Time { return now }) + m.RevokeFor(builder, errBidBlockAverageGasPriceTooLow.Error(), common.Hash{}, 1, bidBlockGasPriceLowRevokeDuration) + + status := m.GetStatus(builder) + if status.Allowed { + t.Fatal("builder should be revoked") + } + if want := now.Add(bidBlockGasPriceLowRevokeDuration); !status.ResetAt.Equal(want) { + t.Fatalf("resetAt: got %s, want %s", status.ResetAt, want) + } + + setBidBlockPermissionClock(m, func() time.Time { return now.Add(bidBlockGasPriceLowRevokeDuration) }) + if !m.IsAllowed(builder) { + t.Fatal("gas price low revoke should expire after the custom duration") + } +} + +func TestBidBlockPermission_RevokeOverwrites(t *testing.T) { + m := NewBidBlockPermissionManager() + builder := common.HexToAddress("0x1") + + m.Revoke(builder, testInsertChainReason, common.HexToHash("0x1"), 1) + m.Revoke(builder, RevokeReasonManual, common.HexToHash("0x2"), 2) + + rec, ok := getBidBlockPermissionRecord(m, builder) + if !ok { + t.Fatal("record expected") + } + if rec.Reason != RevokeReasonManual { + t.Fatalf("most recent reason should win: got %s", rec.Reason) + } + if rec.BlockNum != 2 { + t.Fatalf("most recent blockNum should win: got %d", rec.BlockNum) + } +} + +func TestBidBlockPermission_ExpiresAt24h(t *testing.T) { + m := NewBidBlockPermissionManager() + builder := common.HexToAddress("0x1") + + revokeTime := time.Date(2026, 5, 8, 12, 0, 0, 0, time.UTC) + exactly24hLater := revokeTime.Add(24 * time.Hour) + + setBidBlockPermissionClock(m, func() time.Time { return revokeTime }) + m.Revoke(builder, testInsertChainReason, common.Hash{}, 1) + if m.IsAllowed(builder) { + t.Fatal("freshly revoked builder should be blocked") + } + + setBidBlockPermissionClock(m, func() time.Time { return exactly24hLater }) + if !m.IsAllowed(builder) { + t.Fatal("record at exactly revokedAt + 24h should be expired") + } + if _, ok := getBidBlockPermissionRecord(m, builder); ok { + t.Fatal("getRecord should report expired at revokedAt + 24h") + } +} + +func TestBidBlockPermission_StillRevokedWithin24h(t *testing.T) { + m := NewBidBlockPermissionManager() + builder := common.HexToAddress("0x1") + + // UTC midnight should not reset the revoke; only elapsed time matters. + // This covers the old day-boundary bypass. + revokeTime := time.Date(2026, 5, 8, 23, 59, 59, 0, time.UTC) + setBidBlockPermissionClock(m, func() time.Time { return revokeTime }) + m.Revoke(builder, testInsertChainReason, common.Hash{}, 1) + + justAfterUTCMidnight := time.Date(2026, 5, 9, 0, 0, 1, 0, time.UTC) + setBidBlockPermissionClock(m, func() time.Time { return justAfterUTCMidnight }) + if m.IsAllowed(builder) { + t.Fatal("revoke must not expire just because UTC day rolled over (only 2s elapsed)") + } + + justBefore24h := revokeTime.Add(24*time.Hour - time.Second) + setBidBlockPermissionClock(m, func() time.Time { return justBefore24h }) + if m.IsAllowed(builder) { + t.Fatal("revoke must still be active 1s before the 24h boundary") + } +} + +// Builders revoked at different times should expire independently. +func TestBidBlockPermission_IndependentResetAt(t *testing.T) { + m := NewBidBlockPermissionManager() + a := common.HexToAddress("0xa") + b := common.HexToAddress("0xb") + + t0 := time.Date(2026, 5, 8, 10, 0, 0, 0, time.UTC) + + setBidBlockPermissionClock(m, func() time.Time { return t0 }) + m.Revoke(a, testInsertChainReason, common.Hash{}, 1) + + setBidBlockPermissionClock(m, func() time.Time { return t0.Add(5 * time.Hour) }) + m.Revoke(b, testInsertChainReason, common.Hash{}, 2) + + // Both revoked at t0 + 6h; resetAt fields must be independent. + setBidBlockPermissionClock(m, func() time.Time { return t0.Add(6 * time.Hour) }) + statusA := m.GetStatus(a) + statusB := m.GetStatus(b) + if statusA.Allowed || statusB.Allowed { + t.Fatal("both builders should be revoked at t0 + 6h") + } + if want := t0.Add(24 * time.Hour); !statusA.ResetAt.Equal(want) { + t.Fatalf("A resetAt: got %s, want %s", statusA.ResetAt, want) + } + if want := t0.Add(29 * time.Hour); !statusB.ResetAt.Equal(want) { + t.Fatalf("B resetAt: got %s, want %s", statusB.ResetAt, want) + } + + // At A.RevokedAt + 24h, A's lockout expires but B still has 5h left. + setBidBlockPermissionClock(m, func() time.Time { return t0.Add(24 * time.Hour) }) + if !m.IsAllowed(a) { + t.Fatal("A should be allowed at its own RevokedAt + 24h") + } + if m.IsAllowed(b) { + t.Fatal("B should still be revoked (only 19h elapsed since its own RevokedAt)") + } + + // At B.RevokedAt + 24h, B's lockout also expires. + setBidBlockPermissionClock(m, func() time.Time { return t0.Add(29 * time.Hour) }) + if !m.IsAllowed(b) { + t.Fatal("B should be allowed at its own RevokedAt + 24h") + } +} + +func TestBidBlockPermission_ConcurrentAccess(t *testing.T) { + m := NewBidBlockPermissionManager() + builders := []common.Address{ + common.HexToAddress("0xa"), + common.HexToAddress("0xb"), + common.HexToAddress("0xc"), + } + + var wg sync.WaitGroup + for i := 0; i < 50; i++ { + wg.Add(3) + b := builders[i%len(builders)] + go func() { defer wg.Done(); m.IsAllowed(b) }() + go func() { defer wg.Done(); m.Revoke(b, testInsertChainReason, common.Hash{}, 1) }() + go func() { defer wg.Done(); getBidBlockPermissionRecord(m, b) }() + } + wg.Wait() +} + +func TestBidBlockPermission_ActiveRevokeCount(t *testing.T) { + m := NewBidBlockPermissionManager() + + if got := m.ActiveRevokeCount(); got != 0 { + t.Fatalf("empty manager: got %d, want 0", got) + } + + revokeTime := time.Date(2026, 5, 8, 12, 0, 0, 0, time.UTC) + after24h := revokeTime.Add(24 * time.Hour) + setBidBlockPermissionClock(m, func() time.Time { return revokeTime }) + + a := common.HexToAddress("0xa") + b := common.HexToAddress("0xb") + m.Revoke(a, testInsertChainReason, common.Hash{}, 1) + m.Revoke(b, RevokeReasonManual, common.Hash{}, 2) + + if got := m.ActiveRevokeCount(); got != 2 { + t.Fatalf("two revoked: got %d, want 2", got) + } + + setBidBlockPermissionClock(m, func() time.Time { return after24h }) + if got := m.ActiveRevokeCount(); got != 0 { + t.Fatalf("after revokedAt + 24h: got %d, want 0 (entries are stale, not active)", got) + } +} + +func TestBidBlockPermission_GetStatus(t *testing.T) { + m := NewBidBlockPermissionManager() + builder := common.HexToAddress("0x1") + now := time.Date(2026, 5, 9, 10, 0, 0, 0, time.UTC) + resetAt := now.Add(24 * time.Hour) + setBidBlockPermissionClock(m, func() time.Time { return now }) + + status := m.GetStatus(builder) + if !status.Allowed { + t.Fatal("fresh builder should be allowed") + } + if !status.ResetAt.IsZero() { + t.Fatalf("allowed status should not set resetAt: got %s", status.ResetAt) + } + + hash := common.HexToHash("0xabc") + m.Revoke(builder, testInsertChainReason, hash, 100) + status = m.GetStatus(builder) + if status.Allowed { + t.Fatal("revoked builder should not be allowed") + } + if status.Reason != testInsertChainReason { + t.Fatalf("reason: got %s", status.Reason) + } + if status.BlockHash != hash || status.BlockNum != 100 || !status.RevokedAt.Equal(now) || !status.ResetAt.Equal(resetAt) { + t.Fatalf("status mismatch: %#v", status) + } +} + +func TestBidBlockAdmission_RevokedDoesNotConsumeQuota(t *testing.T) { + permMgr := NewBidBlockPermissionManager() + b := &bidSimulator{ + builders: make(map[common.Address]*builderclient.Client), + pending: make(map[uint64]map[common.Address]map[common.Hash]struct{}), + maxBidsPerBuilder: 2, + } + + builder := common.HexToAddress("0x1") + const blockNum uint64 = 100 + + b.builders[builder] = nil + permMgr.Revoke(builder, testInsertChainReason, common.Hash{}, blockNum-1) + + if !b.ExistBuilder(builder) { + t.Fatal("registered builder must pass ExistBuilder") + } + if permMgr.IsAllowed(builder) { + t.Fatal("revoked builder must fail permission check") + } + + b.pendingMu.RLock() + pendingForBlock := b.pending[blockNum] + b.pendingMu.RUnlock() + if len(pendingForBlock) != 0 { + t.Fatalf("revoked admission must not touch pending map; got %d entries", len(pendingForBlock)) + } + + other := common.HexToAddress("0x2") + otherHash := common.HexToHash("0xbeef") + if err := b.CheckPending(blockNum, other, otherHash); err != nil { + t.Fatalf("active builder should pass CheckPending: %v", err) + } + b.AddPending(blockNum, other, otherHash) + + b.pendingMu.RLock() + otherCount := len(b.pending[blockNum][other]) + revokedCount := len(b.pending[blockNum][builder]) + b.pendingMu.RUnlock() + if otherCount != 1 { + t.Fatalf("active builder should have 1 pending entry; got %d", otherCount) + } + if revokedCount != 0 { + t.Fatalf("revoked builder should have 0 pending entries; got %d", revokedCount) + } +} + +func TestBidBlockAdmission_DisabledDoesNotConsumeQuota(t *testing.T) { + for _, tc := range []struct { + name string + mevEnabled bool + bidBlockEnabled bool + }{ + {name: "BidBlock disabled", mevEnabled: true, bidBlockEnabled: false}, + {name: "MEV disabled", mevEnabled: false, bidBlockEnabled: true}, + } { + t.Run(tc.name, func(t *testing.T) { + miner := &Miner{ + worker: &worker{config: &minerconfig.Config{ + Mev: minerconfig.MevConfig{ + Enabled: &tc.mevEnabled, + BidBlockEnabled: &tc.bidBlockEnabled, + }, + }}, + bidSimulator: &bidSimulator{ + pending: make(map[uint64]map[common.Address]map[common.Hash]struct{}), + }, + } + + _, err := miner.SendBidBlock(context.Background(), &buildertypes.BidBlockArgs{}) + if err == nil || !strings.Contains(err.Error(), "BidBlock disabled") { + t.Fatalf("expected BidBlock disabled error, got %v", err) + } + if len(miner.bidSimulator.pending) != 0 { + t.Fatalf("disabled SendBidBlock must not touch pending map; got %d entries", len(miner.bidSimulator.pending)) + } + }) + } +} + +func TestMinerBidBlockPermission_UsesWorkerManager(t *testing.T) { + m := NewBidBlockPermissionManager() + miner := &Miner{worker: &worker{permMgr: m}} + builder := common.HexToAddress("0x1") + + m.Revoke(builder, testInsertChainReason, common.Hash{}, 1) + if miner.GetBidBlockPermission(builder).Allowed { + t.Fatal("miner should report worker revoke") + } +} + +func TestBidBlockPermission_SetAllowed_Deny(t *testing.T) { + m := NewBidBlockPermissionManager() + builder := common.HexToAddress("0x1") + + m.SetAllowed(builder, false) + if m.IsAllowed(builder) { + t.Fatal("builder should be denied after SetAllowed(false)") + } + rec, ok := getBidBlockPermissionRecord(m, builder) + if !ok { + t.Fatal("record expected after SetAllowed(false)") + } + if rec.Reason != RevokeReasonManual { + t.Fatalf("reason: got %q, want %q", rec.Reason, RevokeReasonManual) + } +} + +func TestBidBlockPermission_SetAllowed_Clear(t *testing.T) { + m := NewBidBlockPermissionManager() + builder := common.HexToAddress("0x1") + + m.Revoke(builder, testInsertChainReason, common.HexToHash("0xabc"), 100) + m.SetAllowed(builder, true) + if !m.IsAllowed(builder) { + t.Fatal("manual SetAllowed(true) should override revoke") + } + if _, ok := getBidBlockPermissionRecord(m, builder); ok { + t.Fatal("record should be cleared") + } +} diff --git a/miner/bid_gas_price.go b/miner/bid_gas_price.go new file mode 100644 index 0000000000..8c30b4f1ab --- /dev/null +++ b/miner/bid_gas_price.go @@ -0,0 +1,41 @@ +// Copyright 2026 The go-ethereum Authors +// This file is part of the go-ethereum library. + +package miner + +import ( + "errors" + "fmt" + "math/big" + + "github.com/ethereum/go-ethereum/core/types" +) + +var errBidBlockAverageGasPriceTooLow = errors.New("BidBlock average gas price too low") + +func validateBidBlockAverageGasPrice( + gasFee *big.Int, + receipts types.Receipts, + systemTxStart int, + minGasPrice *big.Int, +) (*big.Int, uint64, error) { + gasUsed := calcNonSystemGasUsed(receipts[:systemTxStart]) + if gasUsed == 0 { + return nil, 0, nil + } + avgGasPrice := new(big.Int).Div(new(big.Int).Set(gasFee), new(big.Int).SetUint64(gasUsed)) + if avgGasPrice.Cmp(minGasPrice) < 0 { + return avgGasPrice, gasUsed, fmt.Errorf("%w, avg:%v, min:%v", errBidBlockAverageGasPriceTooLow, avgGasPrice, minGasPrice) + } + return avgGasPrice, gasUsed, nil +} + +func calcNonSystemGasUsed( + receipts types.Receipts, +) uint64 { + gasUsed := uint64(0) + for _, receipt := range receipts { + gasUsed += receipt.GasUsed + } + return gasUsed +} diff --git a/miner/bid_gas_price_test.go b/miner/bid_gas_price_test.go new file mode 100644 index 0000000000..c2d4572f68 --- /dev/null +++ b/miner/bid_gas_price_test.go @@ -0,0 +1,48 @@ +// Copyright 2026 The go-ethereum Authors +// This file is part of the go-ethereum library. + +package miner + +import ( + "errors" + "math/big" + "testing" + + "github.com/ethereum/go-ethereum/core/types" +) + +func TestValidateBidBlockAverageGasPriceTooLow(t *testing.T) { + receipts := types.Receipts{{GasUsed: 21_000}} + gasFee := big.NewInt(21_000) + + avg, gasUsed, err := validateBidBlockAverageGasPrice(gasFee, receipts, 1, big.NewInt(2)) + if !errors.Is(err, errBidBlockAverageGasPriceTooLow) { + t.Fatalf("expected low gas price error, got %v", err) + } + if avg.Cmp(big.NewInt(1)) != 0 { + t.Fatalf("avg gas price: got %v, want 1", avg) + } + if gasUsed != 21_000 { + t.Fatalf("gas used: got %d, want 21000", gasUsed) + } +} + +func TestValidateBidBlockAverageGasPriceExcludesSystemTxs(t *testing.T) { + receipts := types.Receipts{ + {GasUsed: 21_000}, + {GasUsed: 21_000}, + {GasUsed: 21_000}, + } + gasFee := big.NewInt(5 * 42_000) + + avg, gasUsed, err := validateBidBlockAverageGasPrice(gasFee, receipts, 2, big.NewInt(5)) + if err != nil { + t.Fatalf("check gas price failed: %v", err) + } + if avg.Cmp(big.NewInt(5)) != 0 { + t.Fatalf("avg gas price: got %v, want 5", avg) + } + if gasUsed != 42_000 { + t.Fatalf("gas used: got %d, want 42000", gasUsed) + } +} diff --git a/miner/bid_simulator.go b/miner/bid_simulator.go index e8d34c20b7..4046ac3238 100644 --- a/miner/bid_simulator.go +++ b/miner/bid_simulator.go @@ -22,6 +22,7 @@ import ( "github.com/ethereum/go-ethereum/core" "github.com/ethereum/go-ethereum/core/txpool" "github.com/ethereum/go-ethereum/core/types" + buildertypes "github.com/ethereum/go-ethereum/core/types/builder" "github.com/ethereum/go-ethereum/event" "github.com/ethereum/go-ethereum/log" "github.com/ethereum/go-ethereum/metrics" @@ -29,10 +30,14 @@ import ( "github.com/ethereum/go-ethereum/miner/minerconfig" "github.com/ethereum/go-ethereum/params" "github.com/ethereum/go-ethereum/rpc" + "github.com/ethereum/go-ethereum/trie" ) const prefetchTxNumber = 50 +// uint256BitLen is the bit width of uint256; a value wider than this cannot fit a tx value. +const uint256BitLen = 256 + var ( bidPreCheckTimer = metrics.NewRegisteredTimer("bid/preCheck", nil) bidTryInterruptTimer = metrics.NewRegisteredTimer("bid/sim/tryInterrupt", nil) @@ -45,6 +50,26 @@ var ( // greedyMergeOnchainCounter counts bids that went through greedy merge and were finally chosen as BUILDER BLOCK. greedyMergeOnchainCounter = metrics.NewRegisteredCounter("bid/greedyMerge/onchain", nil) + + // bidBlockBuildersGauge tracks the distinct registered builders that have + // sent BidBlock since node start (cumulative, in-memory, resets on restart). + bidBlockBuildersGauge = metrics.NewRegisteredGauge("bidblock/sendBidBlock/builders", nil) + + // bidBlockPreCheckTimer measures SendBidBlock admission time from RPC receive + // to successful pre-seal verification, matching the legacy bid/preCheck scope. + bidBlockPreCheckTimer = metrics.NewRegisteredTimer("bidblock/sendBidBlock/preCheck", nil) + + // bidBlockPreSealVerifyTimer measures only preSealVerifyBidBlock duration. + bidBlockPreSealVerifyTimer = metrics.NewRegisteredTimer("bidblock/sendBidBlock/preSealVerify", nil) + + // bidBlockPrepareTimer measures prepareBidBlockTask: the selected BidBlock's + // blob KZG validation + system-tx bind-signing + TxHash recompute, on the + // critical path between selection and seal (fires on success and failure). + bidBlockPrepareTimer = metrics.NewRegisteredTimer("bidblock/prepare/duration", nil) + + // bidBlockVerifyTimer times the sealed-BidBlock InsertChain verify; fires on + // success+failure, so _count = total verifies (verified = _count - bidBlockVerifyFailed). + bidBlockVerifyTimer = metrics.NewRegisteredTimer("bidblock/verify/duration", nil) ) var ( @@ -73,6 +98,7 @@ var ( type bidWorker interface { prepareWork(params *generateParams, witness bool) (*environment, error) etherbase() common.Address + getGasCeil() uint64 getPrefetcher() core.Prefetcher fillTransactions(interruptCh chan int32, env *environment, stopTimer *time.Timer, bidTxs mapset.Set[common.Hash]) (err error) } @@ -85,18 +111,22 @@ type simBidReq struct { // newBidPackage is the warp of a new bid and a feedback channel type newBidPackage struct { - bid *types.Bid + bid *buildertypes.Bid feedback chan error receiveTime int64 } +type newBidBlockPackage struct { + bidBlock *buildertypes.DecodedBidBlock + feedback chan error +} + // bidSimulator is in charge of receiving bid from builders, reporting issue to builders. // And take care of bid simulation, rewards computing, best bid maintaining. type bidSimulator struct { config *minerconfig.MevConfig delayLeftOver time.Duration minGasPrice *big.Int - txMaxGas uint64 // Maximum gas for per transaction(will be removed after Mendel hardfork) chain *core.BlockChain txpool *txpool.TxPool chainConfig *params.ChainConfig @@ -125,45 +155,55 @@ type bidSimulator struct { pending map[uint64]map[common.Address]map[common.Hash]struct{} // blockNumber -> builder -> bidHash -> struct{} bestBidMu sync.RWMutex - bestBid map[common.Hash]*BidRuntime // prevBlockHash -> bidRuntime - bestBidToRun map[common.Hash]*types.Bid // prevBlockHash -> *types.Bid + bestBid map[common.Hash]*BidRuntime // prevBlockHash -> bidRuntime + bestBidToRun map[common.Hash]*buildertypes.Bid // prevBlockHash -> *buildertypes.Bid simBidMu sync.RWMutex simulatingBid map[common.Hash]*BidRuntime // prevBlockHash -> bidRuntime, in the process of simulation bidsToSim map[uint64][]*BidRuntime // blockNumber --> bidRuntime list, used to discard envs maxBidsPerBuilder uint32 // Maximum number of bids allowed per builder per block + + // SendBidBlock fields + bestBidBlockMu sync.RWMutex + bestBidBlock map[common.Hash]*buildertypes.DecodedBidBlock // parentHash -> best bid block + newBidBlockCh chan newBidBlockPackage // channel for incoming bid blocks + + // distinct registered builders that have sent BidBlock since node start + bidBlockBuildersMu sync.Mutex + bidBlockBuilders map[common.Address]struct{} } func newBidSimulator( config *minerconfig.MevConfig, delayLeftOver *time.Duration, minGasPrice *big.Int, - txMaxGas uint64, eth Backend, chainConfig *params.ChainConfig, engine consensus.Engine, bidWorker bidWorker, ) *bidSimulator { b := &bidSimulator{ - config: config, - minGasPrice: minGasPrice, - txMaxGas: txMaxGas, - chain: eth.BlockChain(), - txpool: eth.TxPool(), - chainConfig: chainConfig, - engine: engine, - bidWorker: bidWorker, - exitCh: make(chan struct{}), - chainHeadCh: make(chan core.ChainHeadEvent, chainHeadChanSize), - builders: make(map[common.Address]*builderclient.Client), - simBidCh: make(chan *simBidReq), - newBidCh: make(chan newBidPackage, 100), - pending: make(map[uint64]map[common.Address]map[common.Hash]struct{}), - bestBid: make(map[common.Hash]*BidRuntime), - bestBidToRun: make(map[common.Hash]*types.Bid), - simulatingBid: make(map[common.Hash]*BidRuntime), - bidsToSim: make(map[uint64][]*BidRuntime), + config: config, + minGasPrice: minGasPrice, + chain: eth.BlockChain(), + txpool: eth.TxPool(), + chainConfig: chainConfig, + engine: engine, + bidWorker: bidWorker, + exitCh: make(chan struct{}), + chainHeadCh: make(chan core.ChainHeadEvent, chainHeadChanSize), + builders: make(map[common.Address]*builderclient.Client), + simBidCh: make(chan *simBidReq), + newBidCh: make(chan newBidPackage, 100), + pending: make(map[uint64]map[common.Address]map[common.Hash]struct{}), + bestBid: make(map[common.Hash]*BidRuntime), + bestBidToRun: make(map[common.Hash]*buildertypes.Bid), + simulatingBid: make(map[common.Hash]*BidRuntime), + bidsToSim: make(map[uint64][]*BidRuntime), + bestBidBlock: make(map[common.Hash]*buildertypes.DecodedBidBlock), + newBidBlockCh: make(chan newBidBlockPackage, 100), + bidBlockBuilders: make(map[common.Address]struct{}), } if delayLeftOver != nil { b.delayLeftOver = *delayLeftOver @@ -186,6 +226,7 @@ func newBidSimulator( go b.clearLoop() go b.mainLoop() go b.newBidLoop() + go b.newBidBlockLoop() return b } @@ -297,7 +338,7 @@ func (b *bidSimulator) GetBestBid(prevBlockHash common.Hash) *BidRuntime { } // best bid to run is based on bid's expectedBlockReward before the bid is simulated -func (b *bidSimulator) SetBestBidToRun(prevBlockHash common.Hash, bid *types.Bid) { +func (b *bidSimulator) SetBestBidToRun(prevBlockHash common.Hash, bid *buildertypes.Bid) { b.bestBidMu.Lock() defer b.bestBidMu.Unlock() @@ -305,7 +346,7 @@ func (b *bidSimulator) SetBestBidToRun(prevBlockHash common.Hash, bid *types.Bid } // in case the bid is invalid(invalid GasUsed,Reward,GasPrice...), remove it. -func (b *bidSimulator) DelBestBidToRun(prevBlockHash common.Hash, delBid *types.Bid) { +func (b *bidSimulator) DelBestBidToRun(prevBlockHash common.Hash, delBid *buildertypes.Bid) { b.bestBidMu.Lock() defer b.bestBidMu.Unlock() cur := b.bestBidToRun[prevBlockHash] @@ -317,7 +358,7 @@ func (b *bidSimulator) DelBestBidToRun(prevBlockHash common.Hash, delBid *types. } } -func (b *bidSimulator) GetBestBidToRun(prevBlockHash common.Hash) *types.Bid { +func (b *bidSimulator) GetBestBidToRun(prevBlockHash common.Hash) *buildertypes.Bid { b.bestBidMu.RLock() defer b.bestBidMu.RUnlock() @@ -436,6 +477,8 @@ func (b *bidSimulator) newBidLoop() { continue } + // Pre-check before simulation for fast feedback to the builder; + // simulation would reject these txs anyway via state_transition preCheck. if errCap := b.checkIfBidExceedsTxGasLimit(newBid.bid); errCap != nil { if newBid.feedback != nil { newBid.feedback <- errCap @@ -534,30 +577,21 @@ func (b *bidSimulator) getBlockInterval(parentHeader *types.Header) uint64 { } // checkIfBidExceedsTxGasLimit checks whether any transaction in the bid exceeds the max txn gas. -func (b *bidSimulator) checkIfBidExceedsTxGasLimit(bid *types.Bid) error { - var gasLimitCap uint64 +func (b *bidSimulator) checkIfBidExceedsTxGasLimit(bid *buildertypes.Bid) error { currentHeader := b.chain.CurrentBlock() - if b.chainConfig.IsOsaka(currentHeader.Number, currentHeader.Time) { - gasLimitCap = params.MaxTxGas - } else { - if b.txMaxGas == 0 { - return nil - } - gasLimitCap = b.txMaxGas + if !b.chainConfig.IsOsaka(currentHeader.Number, currentHeader.Time) { + return nil } - - // Scan all txs in the bid to check if any transaction exceeds the gas limit cap for _, tx := range bid.Txs { - if tx.Gas() > gasLimitCap { + if tx.Gas() > params.MaxTxGas { log.Debug("discard bid due to per-tx gas limit", "block", bid.BlockNumber, "bidHash", bid.Hash().TerminalString(), "txHash", tx.Hash().TerminalString(), "txGas", tx.Gas(), - "txGasLimit", gasLimitCap, + "txGasLimit", params.MaxTxGas, ) - - return fmt.Errorf("bid rejected: %w (cap: %d, tx: %d)", core.ErrGasLimitTooHigh, gasLimitCap, tx.Gas()) + return fmt.Errorf("bid rejected: %w (cap: %d, tx: %d)", core.ErrGasLimitTooHigh, params.MaxTxGas, tx.Gas()) } } return nil @@ -568,6 +602,11 @@ func (b *bidSimulator) bidBetterBefore(parentHash common.Hash) time.Time { return bidutil.BidBetterBefore(parentHeader, b.getBlockInterval(parentHeader), b.delayLeftOver, *b.config.BidSimulationLeftOver) } +func (b *bidSimulator) bidMustBefore(parentHash common.Hash) time.Time { + parentHeader := b.chain.GetHeaderByHash(parentHash) + return bidutil.BidMustBefore(parentHeader, b.getBlockInterval(parentHeader), b.delayLeftOver) +} + func (b *bidSimulator) clearLoop() { clearFn := func(parentHash common.Hash, blockNumber uint64) { b.pendingMu.Lock() @@ -611,6 +650,14 @@ func (b *bidSimulator) clearLoop() { } } b.simBidMu.Unlock() + + b.bestBidBlockMu.Lock() + for k, block := range b.bestBidBlock { + if block == nil || block.BlockNumber() <= clearThreshold { + delete(b.bestBidBlock, k) + } + } + b.bestBidBlockMu.Unlock() } for { @@ -632,9 +679,223 @@ func (b *bidSimulator) clearLoop() { } } +// AddBidBlock keeps the best BidBlock for a given parent hash. +func (b *bidSimulator) AddBidBlock(parentHash common.Hash, block *buildertypes.DecodedBidBlock) error { + b.bestBidBlockMu.Lock() + defer b.bestBidBlockMu.Unlock() + + if existing := b.bestBidBlock[parentHash]; existing != nil && block.GasFee.Cmp(existing.GasFee) <= 0 { + return fmt.Errorf("BidBlock gasFee not higher than current best: bidHash=%s got %s, bestBidHash=%s best %s", + block.Hash(), weiToEtherStringF6(block.GasFee), existing.Hash(), weiToEtherStringF6(existing.GasFee)) + } + b.bestBidBlock[parentHash] = block + return nil +} + +// GetBestBidBlock returns the best BidBlock for a given parent hash. +func (b *bidSimulator) GetBestBidBlock(parentHash common.Hash) *buildertypes.DecodedBidBlock { + b.bestBidBlockMu.RLock() + defer b.bestBidBlockMu.RUnlock() + return b.bestBidBlock[parentHash] +} + +// recordBidBlockBuilder adds builder to the cumulative set of registered +// builders that have sent BidBlock and publishes the distinct count. +// The set is kept in memory and resets on restart. +func (b *bidSimulator) recordBidBlockBuilder(builder common.Address) { + b.bidBlockBuildersMu.Lock() + b.bidBlockBuilders[builder] = struct{}{} + count := len(b.bidBlockBuilders) + b.bidBlockBuildersMu.Unlock() + bidBlockBuildersGauge.Update(int64(count)) +} + +// preSealVerifyBidBlock validates a BidBlock before admission. +func (b *bidSimulator) preSealVerifyBidBlock(decoded *buildertypes.DecodedBidBlock) error { + start := time.Now() + defer bidBlockPreSealVerifyTimer.UpdateSince(start) + parliaEngine, ok := b.engine.(*parlia.Parlia) + if !ok { + return errors.New("consensus engine is not parlia") + } + header := decoded.Header + + if header.Coinbase != b.bidWorker.etherbase() { + return fmt.Errorf("invalid coinbase: got %s, want %s", + header.Coinbase.Hex(), b.bidWorker.etherbase().Hex()) + } + parent := b.chain.GetHeaderByHash(header.ParentHash) + if parent == nil { + return consensus.ErrUnknownAncestor + } + expectedGasLimit := core.CalcGasLimit(parent.GasLimit, b.bidWorker.getGasCeil()) + if header.GasLimit != expectedGasLimit { + return fmt.Errorf("invalid gasLimit: got %d, want %d", header.GasLimit, expectedGasLimit) + } + if err := parliaEngine.VerifyUnsealedHeader(b.chain, header, nil); err != nil { + return fmt.Errorf("invalid header: %v", err) + } + if err := parliaEngine.BlockTimeUpperCheck(b.chain, header); err != nil { + return fmt.Errorf("invalid header: %v", err) + } + if txHash := types.DeriveSha(decoded.Txs, trie.NewStackTrie(nil)); header.TxHash != txHash { + return fmt.Errorf("invalid tx root: got %s, want %s", header.TxHash, txHash) + } + + decoded.SystemTxStart, decoded.GasFee = parliaEngine.ExtractBidBlockDepositValue(decoded.Txs) + + // GasFee comes from the deposit tx value; reject overflow before bid selection. + if decoded.GasFee.Sign() <= 0 { + return errors.New("empty gasFee") + } + if decoded.GasFee.BitLen() > uint256BitLen { + return fmt.Errorf("gasFee exceeds uint256: bitLen %d", decoded.GasFee.BitLen()) + } + + // Only cheap sidecar checks run at admission; KZG is checked for the selected BidBlock. + if err := b.validateBidBlockBlobSidecars(decoded); err != nil { + return err + } + + // Per-tx gas cap over user txs only, mirroring SendBid. + for _, tx := range decoded.Txs[:decoded.SystemTxStart] { + if tx.Gas() > params.MaxTxGas { + return fmt.Errorf("%w (cap: %d, tx: %d)", core.ErrGasLimitTooHigh, params.MaxTxGas, tx.Gas()) + } + } + + return parliaEngine.VerifyBidBlockSystemTxs(decoded, parent, decoded.SystemTxStart) +} + +// validateBidBlockBlobSidecars checks cheap sidecar invariants before bid selection. +func (b *bidSimulator) validateBidBlockBlobSidecars(decoded *buildertypes.DecodedBidBlock) error { + header := decoded.Header + blobEligibleBlock := eip4844.IsBlobEligibleBlock(b.chainConfig, header.Number.Uint64(), header.Time) + maxBlobsPerBlock := eip4844.MaxBlobsPerBlock(b.chainConfig, header.Time) + sidecarIndex := 0 + blobCount := 0 + for txIndex, tx := range decoded.Txs[:decoded.SystemTxStart] { + if tx.Type() != types.BlobTxType { + continue + } + if !blobEligibleBlock { + return fmt.Errorf("blob transactions not allowed in block %d (N %% %d != 0)", + header.Number.Uint64(), params.BlobEligibleBlockInterval) + } + if sidecarIndex >= len(decoded.Sidecars) { + return fmt.Errorf("blob info mismatch: sidecars %d, blob txs at least %d", + len(decoded.Sidecars), sidecarIndex+1) + } + sidecar := decoded.Sidecars[sidecarIndex] + if sidecar == nil { + return fmt.Errorf("missing sidecar for blob tx at index %d", txIndex) + } + if sidecar.Version == types.BlobSidecarVersion1 { + return errors.New("cell proof is not supported yet") + } + if sidecar.TxHash != tx.Hash() { + return fmt.Errorf("sidecar's TxHash mismatch with transaction at index %d, want: %v, have: %v", + txIndex, tx.Hash(), sidecar.TxHash) + } + if sidecar.TxIndex != uint64(txIndex) { + return fmt.Errorf("sidecar's TxIndex mismatch with transaction at index %d, want: %d, have: %d", + txIndex, txIndex, sidecar.TxIndex) + } + blobCount += len(sidecar.Blobs) + if blobCount > maxBlobsPerBlock { + return fmt.Errorf("too many blobs in block: have %d, permitted %d", + blobCount, maxBlobsPerBlock) + } + sidecarIndex++ + } + if sidecarIndex != len(decoded.Sidecars) { + return fmt.Errorf("blob info mismatch: sidecars %d, blob txs %d", len(decoded.Sidecars), sidecarIndex) + } + return nil +} + +// sendBidBlock queues a decoded BidBlock for selection. +func (b *bidSimulator) sendBidBlock(_ context.Context, block *buildertypes.DecodedBidBlock) error { + timer := time.NewTimer(1 * time.Second) + defer timer.Stop() + + replyCh := make(chan error, 1) + + select { + case b.newBidBlockCh <- newBidBlockPackage{bidBlock: block, feedback: replyCh}: + b.AddPending(block.BlockNumber(), block.Builder, block.Hash()) + case <-timer.C: + return buildertypes.ErrMevBusy + } + + select { + case reply := <-replyCh: + return reply + case <-timer.C: + return buildertypes.ErrMevBusy + } +} + +// newBidBlockLoop stores the best incoming BidBlock by GasFee. +func (b *bidSimulator) newBidBlockLoop() { + for { + select { + case newBidBlock := <-b.newBidBlockCh: + block := newBidBlock.bidBlock + if !b.isRunning() || !b.receivingBid() { + if newBidBlock.feedback != nil { + newBidBlock.feedback <- fmt.Errorf("BidBlock is discarded, not receiving bids: blockNumber=%d builder=%s bidHash=%s", + block.BlockNumber(), block.Builder, block.Hash()) + } + continue + } + + // Discard stale blocks whose block number is no longer current. + currentBlock := b.chain.CurrentBlock() + if block.BlockNumber() <= currentBlock.Number.Uint64() { + log.Debug("BidBlock: discard stale block", + "blockNumber", block.BlockNumber(), + "builder", block.Builder, + "bidHash", block.Hash()) + if newBidBlock.feedback != nil { + newBidBlock.feedback <- fmt.Errorf("BidBlock is discarded, stale block number: %d, latest block: %d, builder=%s, bidHash=%s", + block.BlockNumber(), currentBlock.Number.Uint64(), block.Builder, block.Hash()) + } + continue + } + + if err := b.AddBidBlock(block.ParentHash(), block); err != nil { + log.Debug("BidBlock: discard BidBlock", + "blockNumber", block.BlockNumber(), + "builder", block.Builder, + "bidHash", block.Hash(), + "gasFee", weiToEtherStringF6(block.GasFee), + "err", err) + if newBidBlock.feedback != nil { + newBidBlock.feedback <- err + } + continue + } + + log.Info("[BID BLOCK ARRIVED]", + "blockNumber", block.BlockNumber(), + "bidHash", block.Hash(), + "builder", block.Builder, + "gasFee", weiToEtherStringF6(block.GasFee), + "txs", len(block.Txs)) + if newBidBlock.feedback != nil { + newBidBlock.feedback <- nil + } + + case <-b.exitCh: + return + } + } +} + // sendBid checks if the bid is already exists or if the builder sends too many bids, // if yes, return error, if not, add bid into newBid chan waiting for judge profit. -func (b *bidSimulator) sendBid(ctx context.Context, bid *types.Bid) error { +func (b *bidSimulator) sendBid(ctx context.Context, bid *buildertypes.Bid) error { timer := time.NewTimer(1 * time.Second) defer timer.Stop() @@ -651,14 +912,14 @@ func (b *bidSimulator) sendBid(ctx context.Context, bid *types.Bid) error { case b.newBidCh <- newBidPackage{bid: bid, feedback: replyCh, receiveTime: receiveTime}: b.AddPending(bid.BlockNumber, bid.Builder, bid.Hash()) case <-timer.C: - return types.ErrMevBusy + return buildertypes.ErrMevBusy } select { case reply := <-replyCh: return reply case <-timer.C: - return types.ErrMevBusy + return buildertypes.ErrMevBusy } } @@ -990,7 +1251,7 @@ func (b *bidSimulator) reportIssue(bidRuntime *BidRuntime, err error) { cli := b.builders[bidRuntime.bid.Builder] if cli != nil { - err = cli.ReportIssue(context.Background(), &types.BidIssue{ + err = cli.ReportIssue(context.Background(), &buildertypes.BidIssue{ Validator: bidRuntime.env.header.Coinbase, Builder: bidRuntime.bid.Builder, BidHash: bidRuntime.bid.Hash(), @@ -1004,7 +1265,7 @@ func (b *bidSimulator) reportIssue(bidRuntime *BidRuntime, err error) { } type BidRuntime struct { - bid *types.Bid + bid *buildertypes.Bid env *environment @@ -1020,7 +1281,7 @@ type BidRuntime struct { greedyMerged bool } -func newBidRuntime(newBid *types.Bid, validatorCommission uint64) (*BidRuntime, error) { +func newBidRuntime(newBid *buildertypes.Bid, validatorCommission uint64) (*BidRuntime, error) { // check the block reward and validator reward of the newBid expectedBlockReward := newBid.GasFee expectedValidatorReward := new(big.Int).Mul(expectedBlockReward, big.NewInt(int64(validatorCommission))) diff --git a/miner/builderclient/builderclient.go b/miner/builderclient/builderclient.go index 9606a92d95..80e9953264 100644 --- a/miner/builderclient/builderclient.go +++ b/miner/builderclient/builderclient.go @@ -3,7 +3,7 @@ package builderclient import ( "context" - "github.com/ethereum/go-ethereum/core/types" + buildertypes "github.com/ethereum/go-ethereum/core/types/builder" "github.com/ethereum/go-ethereum/rpc" ) @@ -28,6 +28,6 @@ func newClient(c *rpc.Client) *Client { } // ReportIssue reports an issue -func (ec *Client) ReportIssue(ctx context.Context, args *types.BidIssue) error { +func (ec *Client) ReportIssue(ctx context.Context, args *buildertypes.BidIssue) error { return ec.c.CallContext(ctx, nil, "mev_reportIssue", args) } diff --git a/miner/miner.go b/miner/miner.go index 99de403eb4..8dd6302c79 100644 --- a/miner/miner.go +++ b/miner/miner.go @@ -60,6 +60,7 @@ type Miner struct { } func New(eth Backend, config *minerconfig.Config, mux *event.TypeMux, engine consensus.Engine) *Miner { + bidBlockPermMgr := NewBidBlockPermissionManager() miner := &Miner{ mux: mux, eth: eth, @@ -67,10 +68,10 @@ func New(eth Backend, config *minerconfig.Config, mux *event.TypeMux, engine con exitCh: make(chan struct{}), startCh: make(chan struct{}), stopCh: make(chan struct{}), - worker: newWorker(config, engine, eth, mux), + worker: newWorker(config, engine, eth, mux, bidBlockPermMgr), } - miner.bidSimulator = newBidSimulator(&config.Mev, config.DelayLeftOver, config.GasPrice, config.TxGasLimit, eth, eth.BlockChain().Config(), engine, miner.worker) + miner.bidSimulator = newBidSimulator(&config.Mev, config.DelayLeftOver, config.GasPrice, eth, eth.BlockChain().Config(), engine, miner.worker) miner.worker.setBestBidFetcher(miner.bidSimulator) miner.wg.Add(1) @@ -235,7 +236,3 @@ func (miner *Miner) BuildPayload(args *BuildPayloadArgs, witness bool) (*Payload func (miner *Miner) GasCeil() uint64 { return miner.worker.getGasCeil() } - -func (miner *Miner) TxGasLimit() uint64 { - return miner.worker.getTxGasLimit() -} diff --git a/miner/miner_mev.go b/miner/miner_mev.go index 7f7b0cf4b6..cd52399639 100644 --- a/miner/miner_mev.go +++ b/miner/miner_mev.go @@ -2,13 +2,16 @@ package miner import ( "context" + "errors" "fmt" "math/big" "time" "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/consensus/parlia" "github.com/ethereum/go-ethereum/core/txpool" "github.com/ethereum/go-ethereum/core/types" + buildertypes "github.com/ethereum/go-ethereum/core/types/builder" "github.com/ethereum/go-ethereum/internal/version" "github.com/ethereum/go-ethereum/log" ) @@ -48,14 +51,133 @@ func (miner *Miner) HasBuilder(builder common.Address) bool { return miner.bidSimulator.ExistBuilder(builder) } -func (miner *Miner) SendBid(ctx context.Context, bidArgs *types.BidArgs) (common.Hash, error) { +func (miner *Miner) GetBidBlockPermission(builder common.Address) buildertypes.BidBlockPermissionStatus { + return miner.worker.permMgr.GetStatus(builder) +} + +func (miner *Miner) SetBidBlockPermission(builder common.Address, allowed bool) { + miner.worker.permMgr.SetAllowed(builder, allowed) +} + +// bidBlockEnabled reports whether SendBidBlock is accepted. +func (miner *Miner) bidBlockEnabled() bool { + if !*miner.worker.config.Mev.Enabled || !*miner.worker.config.Mev.BidBlockEnabled { + return false + } + return miner.bidBlockPasteurActive() +} + +func (miner *Miner) bidBlockPasteurActive() bool { + head := miner.worker.chain.CurrentBlock() + return head != nil && miner.worker.chainConfig.IsPasteur(head.Number, head.Time) +} + +func (miner *Miner) SendBidBlock(ctx context.Context, args *buildertypes.BidBlockArgs) (common.Hash, error) { + if !miner.bidBlockEnabled() { + return common.Hash{}, buildertypes.NewInvalidBidError("BidBlock disabled, fallback to SendBid") + } + + bb := args.BidBlock + bidHash := bb.Hash() + + builder, err := args.EcrecoverSender() + if err != nil { + return common.Hash{}, buildertypes.NewInvalidBidError(fmt.Sprintf("invalid signature: bidHash=%s, err=%v", bidHash, err)) + } + + // Receive marker for the mev-sentry -> validator hop: correlate this bidHash with + // the send-side log for latency. Logged before the gates so rejected arrivals count too. + log.Debug("[BID BLOCK RECEIVED]", + "bidHash", bidHash, + "builder", builder, + "number", bb.Header.Number, + "parentHash", bb.Header.ParentHash, + "txs", len(bb.Transactions)) + + if !miner.bidSimulator.ExistBuilder(builder) { + return common.Hash{}, buildertypes.NewInvalidBidError(fmt.Sprintf("builder is not registered: builder=%s, bidHash=%s", builder, bidHash)) + } + miner.bidSimulator.recordBidBlockBuilder(builder) + + // Check permission before CheckPending so rejected BidBlocks do not use quota. + if !miner.worker.permMgr.IsAllowed(builder) { + return common.Hash{}, buildertypes.NewBidBlockPermissionRevokedError("builder BidBlock permission revoked, fallback to SendBid") + } + + if len(bb.Transactions) == 0 { + return common.Hash{}, buildertypes.NewInvalidBidError("empty BidBlock txs") + } + blockNumber := bb.Header.Number.Uint64() + parentHash := bb.Header.ParentHash + parent := miner.bidSimulator.chain.GetHeaderByHash(parentHash) + if parent == nil { + return common.Hash{}, buildertypes.NewInvalidBidError(fmt.Sprintf("parent not found: %s, bidHash=%s", parentHash.Hex(), bidHash)) + } + + // Security: validators must self-produce hard-fork activation blocks. + if miner.worker.chainConfig.IsOnPasteur(bb.Header.Number, parent.Time, bb.Header.Time) { + return common.Hash{}, buildertypes.NewInvalidBidError(fmt.Sprintf( + "BidBlock disabled on hard-fork activation block %d, fallback to SendBid", blockNumber)) + } + if err := miner.bidSimulator.CheckPending(blockNumber, builder, bidHash); err != nil { + return common.Hash{}, err + } + + bidMustBefore := miner.bidSimulator.bidMustBefore(parentHash) + if timeout := time.Until(bidMustBefore); timeout <= 0 { + return common.Hash{}, buildertypes.NewBidBlockTooLateError(fmt.Sprintf("too late, expected before %s, appeared %s later, bidHash=%s", + bidMustBefore, common.PrettyDuration(timeout), bidHash)) + } + + decoded, err := args.ToDecodedBidBlock(builder) + if err != nil { + return common.Hash{}, buildertypes.NewInvalidBidError(fmt.Sprintf("failed to decode bid block: bidHash=%s, err=%v", bidHash, err)) + } + + // Validator owns the entire Extra: overwrite builder's bytes with the operator-configured + // vanity and let SetExtraData rebuild forkhash + validators + turnLength + reserved seal + // space. This runs before preSealVerifyBidBlock so VerifyUnsealedHeader validates the + // validator-constructed Extra rather than the builder's. + parliaEngine, ok := miner.worker.engine.(*parlia.Parlia) + if !ok { + return common.Hash{}, errors.New("consensus engine is not parlia") + } + miner.worker.confMu.RLock() + decoded.Header.Extra = common.CopyBytes(miner.worker.extra) + miner.worker.confMu.RUnlock() + if err := parliaEngine.SetExtraData(miner.worker.chain, decoded.Header); err != nil { + return common.Hash{}, buildertypes.NewInvalidBidError(fmt.Sprintf("set extra data: %v", err)) + } + // Record MEV v2 (bidblock path) source and builder address. + setBidMevInfo(decoded.Header, builder, true) + + if err := miner.bidSimulator.preSealVerifyBidBlock(decoded); err != nil { + log.Warn("BidBlock pre-seal verification failed", + "block", blockNumber, + "builder", builder, + "bidHash", decoded.Hash(), + "err", err) + return common.Hash{}, buildertypes.NewBidBlockPreSealVerifyError(fmt.Sprintf("pre-seal verify failed: bidHash=%s, err=%v", bidHash, err)) + } + if receiveTime, ok := ctx.Value("receiveTime").(int64); ok { + bidBlockPreCheckTimer.UpdateSince(time.UnixMilli(receiveTime)) + } + + if err := miner.bidSimulator.sendBidBlock(ctx, decoded); err != nil { + return common.Hash{}, err + } + + return bidHash, nil +} + +func (miner *Miner) SendBid(ctx context.Context, bidArgs *buildertypes.BidArgs) (common.Hash, error) { builder, err := bidArgs.EcrecoverSender() if err != nil { - return common.Hash{}, types.NewInvalidBidError(fmt.Sprintf("invalid signature:%v", err)) + return common.Hash{}, buildertypes.NewInvalidBidError(fmt.Sprintf("invalid signature:%v", err)) } if !miner.bidSimulator.ExistBuilder(builder) { - return common.Hash{}, types.NewInvalidBidError("builder is not registered") + return common.Hash{}, buildertypes.NewInvalidBidError("builder is not registered") } err = miner.bidSimulator.CheckPending(bidArgs.RawBid.BlockNumber, builder, bidArgs.RawBid.Hash()) @@ -66,7 +188,7 @@ func (miner *Miner) SendBid(ctx context.Context, bidArgs *types.BidArgs) (common signer := types.MakeSigner(miner.worker.chainConfig, big.NewInt(int64(bidArgs.RawBid.BlockNumber)), uint64(time.Now().Unix())) bid, err := bidArgs.ToBid(builder, signer) if err != nil { - return common.Hash{}, types.NewInvalidBidError(fmt.Sprintf("fail to convert bidArgs to bid, %v", err)) + return common.Hash{}, buildertypes.NewInvalidBidError(fmt.Sprintf("fail to convert bidArgs to bid, %v", err)) } bidBetterBefore := miner.bidSimulator.bidBetterBefore(bidArgs.RawBid.ParentHash) @@ -89,7 +211,7 @@ func (miner *Miner) SendBid(ctx context.Context, bidArgs *types.BidArgs) (common // startAsyncBlobValidation uses a fixed-size worker pool to validate blob // transactions in the background (field checks + KZG proof verification). // Results are stored per-tx in bid.BlobValResults keyed by tx hash. -func startAsyncBlobValidation(bid *types.Bid) { +func startAsyncBlobValidation(bid *buildertypes.Bid) { type blobJob struct { tx *types.Transaction ch chan error @@ -131,14 +253,14 @@ func startAsyncBlobValidation(bid *types.Bid) { } } -func (miner *Miner) MevParams() *types.MevParams { +func (miner *Miner) MevParams() *buildertypes.MevParams { builderFeeCeil, ok := big.NewInt(0).SetString(*miner.worker.config.Mev.BuilderFeeCeil, 10) if !ok { log.Error("failed to parse builder fee ceil", "BuilderFeeCeil", *miner.worker.config.Mev.BuilderFeeCeil) return nil } - return &types.MevParams{ + return &buildertypes.MevParams{ ValidatorCommission: *miner.worker.config.Mev.ValidatorCommission, BidSimulationLeftOver: *miner.worker.config.Mev.BidSimulationLeftOver, NoInterruptLeftOver: *miner.worker.config.Mev.NoInterruptLeftOver, @@ -146,6 +268,7 @@ func (miner *Miner) MevParams() *types.MevParams { GasCeil: miner.worker.config.GasCeil, GasPrice: miner.worker.config.GasPrice, BuilderFeeCeil: builderFeeCeil, + BidBlockEnabled: miner.bidBlockEnabled(), Version: version.Semantic, } } diff --git a/miner/miner_mev_test.go b/miner/miner_mev_test.go index abd4627099..96f425d004 100644 --- a/miner/miner_mev_test.go +++ b/miner/miner_mev_test.go @@ -2,11 +2,14 @@ package miner import ( "crypto/rand" + "errors" + "strings" "testing" "github.com/consensys/gnark-crypto/ecc/bls12-381/fr" gokzg4844 "github.com/crate-crypto/go-eth-kzg" "github.com/ethereum/go-ethereum/core/types" + buildertypes "github.com/ethereum/go-ethereum/core/types/builder" "github.com/ethereum/go-ethereum/crypto" "github.com/ethereum/go-ethereum/crypto/kzg4844" "github.com/ethereum/go-ethereum/params" @@ -72,7 +75,7 @@ func TestStartAsyncBlobValidation_InvalidProof(t *testing.T) { sidecar.Proofs[0][0] ^= 0xff tx := makeSignedBlobTx(0, sidecar) - bid := &types.Bid{ + bid := &buildertypes.Bid{ Txs: types.Transactions{tx}, } startAsyncBlobValidation(bid) @@ -85,3 +88,22 @@ func TestStartAsyncBlobValidation_InvalidProof(t *testing.T) { t.Fatal("expected error for invalid KZG proof") } } + +func TestValidateBidBlockBlobTxs_InvalidProof(t *testing.T) { + sidecar := validBlobSidecar(1) + sidecar.Proofs[0][0] ^= 0xff + + tx := makeSignedBlobTx(0, sidecar).WithoutBlobTxSidecar() + blockSidecar := &types.BlobSidecar{ + BlobTxSidecar: *sidecar, + TxHash: tx.Hash(), + TxIndex: 0, + } + if err := validateBidBlockBlobTxs(&types.Header{}, []*types.Transaction{tx}, types.BlobSidecars{blockSidecar}, 1); err == nil { + t.Fatal("expected error for invalid BidBlock blob proof") + } else if !errors.Is(err, errInvalidBidBlockBlobTx) { + t.Fatalf("expected invalid BidBlock blob tx error, got %v", err) + } else if !strings.Contains(err.Error(), "BidBlock blob validation failed") { + t.Fatalf("unexpected error message: %v", err) + } +} diff --git a/miner/minerconfig/config.go b/miner/minerconfig/config.go index 5b2df67696..c024c2e325 100644 --- a/miner/minerconfig/config.go +++ b/miner/minerconfig/config.go @@ -54,6 +54,9 @@ var ( defaultBuilderFeeCeil = "0" defaultValidatorCommission = uint64(100) defaultMaxBidsPerBuilder = uint32(2) // Simple strategy: send one bid early, another near deadline + // MEV validators accept SendBidBlock by default; the RPC stays gated on the + // Pasteur fork and can be disabled via Mev.BidBlockEnabled=false. + defaultBidBlockEnabled = true ) // Config is the configuration parameters of mining. @@ -68,7 +71,6 @@ type Config struct { VoteEnable bool // Whether to vote when mining MaxWaitProposalInSecs *uint64 `toml:",omitempty"` // The maximum time to wait for the proposal to be done, it's aimed to prevent validator being slashed when restarting DisableVoteAttestation bool // Whether to skip assembling vote attestation - TxGasLimit uint64 // Maximum gas for per transaction(will be removed after Mendel hardfork) Mev MevConfig // Mev configuration } @@ -98,6 +100,7 @@ type BuilderConfig struct { type MevConfig struct { Enabled *bool `toml:",omitempty"` // Whether to enable Mev or not + BidBlockEnabled *bool `toml:",omitempty"` // Whether to accept SendBidBlock RPC (BEP-675); coexists with legacy SendBid GreedyMergeTx *bool `toml:",omitempty"` // Whether to merge local transactions to the bid BuilderFeeCeil *string `toml:",omitempty"` // The maximum builder fee of a bid SentryURL string // The url of Mev sentry @@ -110,6 +113,7 @@ type MevConfig struct { var DefaultMevConfig = MevConfig{ Enabled: &defaultMevEnabled, + BidBlockEnabled: &defaultBidBlockEnabled, GreedyMergeTx: &defaultGreedyMergeTx, BuilderFeeCeil: &defaultBuilderFeeCeil, SentryURL: "", @@ -145,6 +149,10 @@ func ApplyDefaultMinerConfig(cfg *Config) { cfg.Mev.Enabled = &defaultMevEnabled log.Info("ApplyDefaultMinerConfig", "Mev.Enabled", *cfg.Mev.Enabled) } + if cfg.Mev.BidBlockEnabled == nil { + cfg.Mev.BidBlockEnabled = &defaultBidBlockEnabled + log.Info("ApplyDefaultMinerConfig", "Mev.BidBlockEnabled", *cfg.Mev.BidBlockEnabled) + } if cfg.Mev.BuilderFeeCeil == nil { cfg.Mev.BuilderFeeCeil = &defaultBuilderFeeCeil log.Info("ApplyDefaultMinerConfig", "Mev.BuilderFeeCeil", *cfg.Mev.BuilderFeeCeil) diff --git a/miner/worker.go b/miner/worker.go index c275ea8f11..93a79b1618 100644 --- a/miner/worker.go +++ b/miner/worker.go @@ -40,6 +40,7 @@ import ( "github.com/ethereum/go-ethereum/core/systemcontracts" "github.com/ethereum/go-ethereum/core/txpool" "github.com/ethereum/go-ethereum/core/types" + buildertypes "github.com/ethereum/go-ethereum/core/types/builder" "github.com/ethereum/go-ethereum/core/vm" "github.com/ethereum/go-ethereum/event" "github.com/ethereum/go-ethereum/log" @@ -77,6 +78,15 @@ var ( inturnBlocksGauge = metrics.NewRegisteredGauge("worker/inturnBlocks", nil) bestBidGasUsedGauge = metrics.NewRegisteredGauge("worker/bestBidGasUsed", nil) // MGas bestWorkGasUsedGauge = metrics.NewRegisteredGauge("worker/bestWorkGasUsed", nil) // MGas + bidBlockExistGauge = metrics.NewRegisteredGauge("worker/bidBlockExist", nil) + bidBlockWinGauge = metrics.NewRegisteredGauge("worker/bidBlockWin", nil) + bidBlockCommitGauge = metrics.NewRegisteredGauge("worker/bidBlockCommit", nil) + bidBlockGasUsedGauge = metrics.NewRegisteredGauge("worker/bidBlockGasUsed", nil) // MGas + bidBlockRevokeGauge = metrics.NewRegisteredGauge("worker/bidBlockRevoke", nil) // cumulative revoke count + // bidBlockVerifyFailedGauge counts sealed BidBlocks that failed async InsertChain verification (cumulative). + bidBlockVerifyFailedGauge = metrics.NewRegisteredGauge("worker/bidBlockVerifyFailed", nil) + // bidBlockRevokedBuildersGauge snapshots how many builders are revoked, taken at each revoke. + bidBlockRevokedBuildersGauge = metrics.NewRegisteredGauge("worker/bidBlockRevokedBuilders", nil) writeBlockTimer = metrics.NewRegisteredTimer("worker/writeblock", nil) finalizeBlockTimer = metrics.NewRegisteredTimer("worker/finalizeblock", nil) @@ -128,6 +138,8 @@ type task struct { state *state.StateDB block *types.Block + bidBlockInfo *bidBlockTaskInfo + createdAt time.Time miningStartAt time.Time } @@ -178,6 +190,7 @@ type getWorkReq struct { type bidFetcher interface { GetBestBid(parentHash common.Hash) *BidRuntime GetSimulatingBid(prevBlockHash common.Hash) *BidRuntime + GetBestBidBlock(parentHash common.Hash) *buildertypes.DecodedBidBlock } // worker is the main object which takes care of submitting new work to consensus engine @@ -189,6 +202,7 @@ type worker struct { chainConfig *params.ChainConfig engine consensus.Engine eth Backend + permMgr *BidBlockPermissionManager prio []common.Address // A list of senders to prioritize chain *core.BlockChain @@ -234,7 +248,10 @@ type worker struct { resubmitHook func(time.Duration, time.Duration) // Method to call upon updating resubmitting interval. } -func newWorker(config *minerconfig.Config, engine consensus.Engine, eth Backend, mux *event.TypeMux) *worker { +func newWorker(config *minerconfig.Config, engine consensus.Engine, eth Backend, mux *event.TypeMux, permMgr *BidBlockPermissionManager) *worker { + if permMgr == nil { + permMgr = NewBidBlockPermissionManager() + } chainConfig := eth.BlockChain().Config() prefetcher := core.NewStatePrefetcher(chainConfig, eth.BlockChain().HeadChain()) if config.Mev.Enabled != nil && *config.Mev.Enabled { @@ -246,6 +263,7 @@ func newWorker(config *minerconfig.Config, engine consensus.Engine, eth Backend, chainConfig: chainConfig, engine: engine, eth: eth, + permMgr: permMgr, chain: eth.BlockChain(), mux: mux, coinbase: config.Etherbase, @@ -315,12 +333,6 @@ func (w *worker) getGasCeil() uint64 { return w.config.GasCeil } -func (w *worker) getTxGasLimit() uint64 { - w.confMu.RLock() - defer w.confMu.RUnlock() - return w.config.TxGasLimit -} - // setExtra sets the content used to initialize the block extra field. func (w *worker) setExtra(extra []byte) { w.confMu.Lock() @@ -580,6 +592,17 @@ func (w *worker) resultLoop() { log.Error("Block found but no relative pending task", "number", block.Number(), "sealhash", sealhash, "hash", hash) continue } + + if !w.recordMinedBlock(block) { + continue + } + + // BidBlock path: broadcast first, then InsertChain for async verification + if task.bidBlockInfo != nil { + w.handleBidBlockResult(block, task) + continue + } + // Different block could share same sealhash, deep copy here to prevent write-write conflict. var ( receipts = make([]*types.Receipt, len(task.receipts)) @@ -607,34 +630,6 @@ func (w *worker) resultLoop() { logs = append(logs, receipt.Logs...) } - if prev, ok := w.recentMinedBlocks.Get(block.NumberU64()); ok { - doubleSign := false - prevParents := prev - if slices.Contains(prevParents, block.ParentHash()) { - log.Error("Reject Double Sign!!", "block", block.NumberU64(), - "hash", block.Hash(), - "root", block.Root(), - "ParentHash", block.ParentHash()) - doubleSign = true - } - if doubleSign { - continue - } - prevParents = append(prevParents, block.ParentHash()) - w.recentMinedBlocks.Add(block.NumberU64(), prevParents) - } else { - // Add() will call removeOldest internally to remove the oldest element - // if the LRU Cache is full - w.recentMinedBlocks.Add(block.NumberU64(), []common.Hash{block.ParentHash()}) - } - - // add BAL to the block - bal := task.state.GetEncodedBlockAccessList(block) - if bal != nil && w.engine.SignBAL(bal) == nil { - block = block.WithBAL(bal) - } - task.state.DumpAccessList(block) - // Commit block and state to database. start := time.Now() status, err := w.chain.WriteBlockAndSetHead(block, receipts, logs, task.state, w.mux) @@ -651,7 +646,7 @@ func (w *worker) resultLoop() { stats.SendBlockTime.Store(time.Now().UnixMilli()) stats.StartMiningTime.Store(task.miningStartAt.UnixMilli()) log.Info("Successfully seal and write new block", "number", block.Number(), "hash", hash, "time", block.Header().MilliTimestamp(), "sealhash", sealhash, - "block size(noBal)", block.Size(), "balSize", block.BALSize(), "elapsed", common.PrettyDuration(time.Since(task.createdAt))) + "block size", block.Size(), "elapsed", common.PrettyDuration(time.Since(task.createdAt))) w.mux.Post(core.NewMinedBlockEvent{Block: block}) case <-w.exitCh: @@ -660,6 +655,26 @@ func (w *worker) resultLoop() { } } +// recordMinedBlock records the mined parent for this height and rejects repeat signing. +func (w *worker) recordMinedBlock(block *types.Block) bool { + if prev, ok := w.recentMinedBlocks.Get(block.NumberU64()); ok { + if slices.Contains(prev, block.ParentHash()) { + log.Error("Reject Double Sign!!", "block", block.NumberU64(), + "hash", block.Hash(), + "root", block.Root(), + "ParentHash", block.ParentHash()) + return false + } + prevParents := append(prev, block.ParentHash()) + w.recentMinedBlocks.Add(block.NumberU64(), prevParents) + } else { + // Add() will call removeOldest internally to remove the oldest element + // if the LRU Cache is full. + w.recentMinedBlocks.Add(block.NumberU64(), []common.Hash{block.ParentHash()}) + } + return true +} + // makeEnv creates a new environment for the sealing block. func (w *worker) makeEnv(parent *types.Header, header *types.Header, coinbase common.Address, prevEnv *environment, witness bool) (*environment, error) { @@ -1054,10 +1069,6 @@ func (w *worker) fillTransactions(interruptCh chan int32, env *environment, stop filter.BlobFee = uint256.MustFromBig(eip4844.CalcBlobFee(w.chainConfig, env.header)) } - if cap := w.getTxGasLimit(); cap > 0 { - filter.GasLimitCap = cap - } - if w.chainConfig.IsOsaka(env.header.Number, env.header.Time) { filter.GasLimitCap = params.MaxTxGas } @@ -1208,6 +1219,26 @@ func (w *worker) generateWork(genParam *generateParams, witness bool) *newPayloa } } +// delay returns the time budget for local block building. +// For the last block in a validator's turn it caps the budget to BlockInterval/4, +// giving the next validator enough lead time to avoid producing an empty block. +// (post-Fermi: 450ms interval, ~120ms one-way p2p delay) +func (w *worker) delay(header *types.Header, leftOver *time.Duration) *time.Duration { + d := w.engine.Delay(w.chain, header, leftOver) + if d == nil { + return nil + } + if p, ok := w.engine.(*parlia.Parlia); ok && p.IsLastBlockInTurn(w.chain, header) { + blockInterval, err := p.BlockInterval(w.chain, header) + if err == nil { + if cap := time.Duration(blockInterval) * time.Millisecond / 4; *d > cap { + return &cap + } + } + } + return d +} + // commitWork generates several new sealing tasks based on the parent block // and submit them to the sealer. func (w *worker) commitWork(interruptCh chan int32, timestamp int64) { @@ -1265,7 +1296,7 @@ LOOP: prevWork = work workList = append(workList, work) - delay := w.engine.Delay(w.chain, work.header, w.config.DelayLeftOver) + delay := w.delay(work.header, w.config.DelayLeftOver) if delay == nil { log.Warn("commitWork delay is nil, something is wrong") stopTimer = nil @@ -1348,7 +1379,7 @@ LOOP: log.Debug("commitWork interruptCh closed, new block imported or resubmit triggered") return case ev := <-txsCh: - delay := w.engine.Delay(w.chain, work.header, w.config.DelayLeftOver) + delay := w.delay(work.header, w.config.DelayLeftOver) log.Debug("commitWork txsCh arrived", "fillDuration", fillDuration.String(), "delay", delay.String(), "work.tcount", work.tcount, "newTxsNum", newTxsNum, "len(ev.Txs)", len(ev.Txs)) @@ -1398,8 +1429,18 @@ LOOP: // when out-turn, use bestWork to prevent bundle leakage. // when in-turn, compare with remote work. + var bestBid *BidRuntime + var bestBidBlock *buildertypes.DecodedBidBlock + var bidBlockCommitted bool + var bidBlockFallback bool + var simBidBlockReward *uint256.Int + var simBidValidatorReward *uint256.Int + var localValidatorReward *uint256.Int if w.bidFetcher != nil && bestWork.header.Difficulty.Cmp(diffInTurn) == 0 { inturnBlocksGauge.Inc(1) + localValidatorReward = new(uint256.Int).Mul(bestReward, uint256.NewInt(*w.config.Mev.ValidatorCommission)) + localValidatorReward.Div(localValidatorReward, uint256.NewInt(10000)) + // We want to start sealing the block as late as possible here if mev is enabled, so we could give builder the chance to send their final bid. // Time left till sealing the block. tillSealingTime := time.Until(time.UnixMilli(int64(bestWork.header.MilliTimestamp()))) - *w.config.DelayLeftOver @@ -1418,44 +1459,72 @@ LOOP: } } - bestBid := w.bidFetcher.GetBestBid(bestWork.header.ParentHash) - + // Stage 1 candidate A — legacy SendBid (simBid). + bestBid = w.bidFetcher.GetBestBid(bestWork.header.ParentHash) if bestBid != nil { bidExistGauge.Inc(1) bestBidGasUsedGauge.Update(int64(bestBid.bid.GasUsed) / 1_000_000) bestWorkGasUsedGauge.Update(int64(bestWork.header.GasUsed) / 1_000_000) - - log.Debug("BidSimulator: final compare", "block", bestWork.header.Number.Uint64(), - "localBlockReward", bestReward.String(), - "bidBlockReward", bestBid.packedBlockReward.String()) + simBidBlockReward = uint256.MustFromBig(bestBid.packedBlockReward) + simBidValidatorReward = uint256.MustFromBig(bestBid.packedValidatorReward) } - if bestBid != nil && bestReward.CmpBig(bestBid.packedBlockReward) < 0 { - // localValidatorReward is the reward for the validator self by the local block. - localValidatorReward := new(uint256.Int).Mul(bestReward, uint256.NewInt(*w.config.Mev.ValidatorCommission)) - localValidatorReward.Div(localValidatorReward, uint256.NewInt(10000)) - - log.Debug("BidSimulator: final compare", "block", bestWork.header.Number.Uint64(), - "localValidatorReward", localValidatorReward.String(), - "bidValidatorReward", bestBid.packedValidatorReward.String()) + // Stage 1 candidate B — SendBidBlock. + bestBidBlock = w.bidFetcher.GetBestBidBlock(parentHash) + if bestBidBlock != nil { + bidBlockExistGauge.Inc(1) + } + } - // blockReward(benefits delegators) and validatorReward(benefits the validator) are both optimal - if localValidatorReward.CmpBig(bestBid.packedValidatorReward) < 0 { - bidWinGauge.Inc(1) - if bestBid.greedyMerged { - greedyMergeOnchainCounter.Inc(1) - } + if bestBidBlock != nil && w.selectBidBlock(bestBidBlock, simBidBlockReward, simBidValidatorReward, bestReward) { + bidBlockWinGauge.Inc(1) + task, err := w.prepareBidBlockTask(bestBidBlock, start) + if err != nil { + log.Error("Failed to prepare bid block, fallback", + "builder", bestBidBlock.Builder, + "err", err) + bidBlockFallback = true + } else { + systemTxCount := len(bestBidBlock.Txs) - bestBidBlock.SystemTxStart + w.enqueueBidBlockTask(task, systemTxCount) + bidBlockCommitted = true + bidBlockCommitGauge.Inc(1) + bidBlockGasUsedGauge.Update(int64(bestBidBlock.Header.GasUsed) / 1_000_000) + bestWorkGasUsedGauge.Update(int64(bestWork.header.GasUsed) / 1_000_000) + } + } - bestWork = bestBid.env + if bidBlockCommitted { + if w.current != nil { + w.current.discard() + w.current = nil + } + return + } - log.Info("[BUILDER BLOCK]", - "block", bestWork.header.Number.Uint64(), - "builder", bestBid.bid.Builder, - "blockReward", weiToEtherStringF6(bestBid.packedBlockReward), - "validatorReward", weiToEtherStringF6(bestBid.packedValidatorReward), - "bid", bestBid.bid.Hash().TerminalString(), - ) + // simBid fallback. Re-runs the legacy dual-threshold gate against simBid + // whenever no BidBlock is being committed. + if bestBid != nil { + if bestReward.Cmp(simBidBlockReward) < 0 && + localValidatorReward.Cmp(simBidValidatorReward) < 0 { + bidWinGauge.Inc(1) + if bestBid.greedyMerged { + greedyMergeOnchainCounter.Inc(1) + } + bestWork = bestBid.env + // Record MEV v1 (bid path) source and builder address. + setBidMevInfo(bestWork.header, bestBid.bid.Builder, false) + logMsg := "[BUILDER BLOCK]" + if bidBlockFallback { + logMsg = "[BUILDER BLOCK] (simBid fallback)" } + log.Info(logMsg, + "block", bestWork.header.Number.Uint64(), + "builder", bestBid.bid.Builder, + "blockReward", weiToEtherStringF6(simBidBlockReward.ToBig()), + "validatorReward", weiToEtherStringF6(simBidValidatorReward.ToBig()), + "bid", bestBid.bid.Hash().TerminalString(), + ) } } diff --git a/miner/worker_test.go b/miner/worker_test.go index e0fab878b6..cc1f241bef 100644 --- a/miner/worker_test.go +++ b/miner/worker_test.go @@ -17,6 +17,7 @@ package miner // TOFIX import ( + "bytes" "math/big" "testing" "time" @@ -26,16 +27,19 @@ import ( "github.com/ethereum/go-ethereum/consensus" "github.com/ethereum/go-ethereum/consensus/clique" "github.com/ethereum/go-ethereum/consensus/ethash" + "github.com/ethereum/go-ethereum/consensus/parlia" "github.com/ethereum/go-ethereum/core" "github.com/ethereum/go-ethereum/core/rawdb" "github.com/ethereum/go-ethereum/core/txpool" "github.com/ethereum/go-ethereum/core/txpool/legacypool" "github.com/ethereum/go-ethereum/core/types" + buildertypes "github.com/ethereum/go-ethereum/core/types/builder" "github.com/ethereum/go-ethereum/crypto" "github.com/ethereum/go-ethereum/ethdb" "github.com/ethereum/go-ethereum/event" "github.com/ethereum/go-ethereum/miner/minerconfig" "github.com/ethereum/go-ethereum/params" + "github.com/ethereum/go-ethereum/trie" "github.com/holiman/uint256" ) @@ -161,7 +165,7 @@ func (b *testWorkerBackend) newRandomTx(creation bool) *types.Transaction { func newTestWorker(t *testing.T, chainConfig *params.ChainConfig, engine consensus.Engine, db ethdb.Database, blocks int) (*worker, *testWorkerBackend) { backend := newTestWorkerBackend(t, chainConfig, engine, db, blocks) backend.txPool.Add(pendingTxs, true) - w := newWorker(testConfig, engine, backend, new(event.TypeMux)) + w := newWorker(testConfig, engine, backend, new(event.TypeMux), NewBidBlockPermissionManager()) w.setEtherbase(testBankAddress) return w, backend } @@ -210,6 +214,91 @@ func TestGenerateAndImportBlock(t *testing.T) { } } +func TestCommitBidBlockPreservesBuilderExecutionHeaderFields(t *testing.T) { + // TODO: rewrite this test with ParliaTestChainConfig + a parlia-formatted + // genesis (vanity + validator + seal) so the snapshot bootstrap inside + // SetExtraData / prepareValidators succeeds. The current TestChainConfig + // has no parlia config and the empty genesis has no validator bytes, so + // prepareBidBlockTask returns "invalid validators bytes" before any of the + // preservation assertions can run. + t.Skip("needs parlia-formatted genesis; see TODO above") + engine := parlia.New(params.TestChainConfig, rawdb.NewMemoryDatabase(), nil, common.Hash{}) + defer engine.Close() + chain, err := core.NewBlockChain(rawdb.NewMemoryDatabase(), &core.Genesis{Config: params.TestChainConfig}, ethash.NewFaker(), nil) + if err != nil { + t.Fatalf("core.NewBlockChain failed: %v", err) + } + defer chain.Stop() + w := &worker{ + chainConfig: params.TestChainConfig, + chain: chain, + engine: engine, + taskCh: make(chan *task, 1), + exitCh: make(chan struct{}), + } + w.running.Store(true) + + tx := types.NewTransaction(0, common.Address{0x1}, big.NewInt(1), params.TxGas, big.NewInt(1), nil) + receiptHash := common.Hash{0x11} + root := common.Hash{0x22} + var bloom types.Bloom + bloom[0] = 0x33 + + builderUncleHash := common.Hash{0xbb} + decoded := &buildertypes.DecodedBidBlock{ + Header: &types.Header{ + Number: big.NewInt(1), + ParentHash: chain.Genesis().Hash(), + UncleHash: builderUncleHash, + Root: root, + ReceiptHash: receiptHash, + Bloom: bloom, + GasUsed: 21000, + Extra: []byte{0xaa, 0xbb}, + }, + Txs: types.Transactions{tx}, + GasFee: big.NewInt(1), + SystemTxStart: 1, // no trailing unsigned system txs in this test + } + w.extra = []byte{0x44, 0x55} + + task, err := w.prepareBidBlockTask(decoded, time.Now()) + if err != nil { + t.Fatalf("prepareBidBlockTask failed: %v", err) + } + + block := task.block + if block.ReceiptHash() != receiptHash { + t.Fatalf("receipt hash mismatch: got %s want %s", block.ReceiptHash(), receiptHash) + } + if block.Root() != root { + t.Fatalf("root mismatch: got %s want %s", block.Root(), root) + } + if block.Bloom() != bloom { + t.Fatalf("bloom mismatch") + } + if block.GasUsed() != decoded.Header.GasUsed { + t.Fatalf("gas used mismatch: got %d want %d", block.GasUsed(), decoded.Header.GasUsed) + } + wantTxHash := types.DeriveSha(types.Transactions{tx}, trie.NewStackTrie(nil)) + if block.TxHash() != wantTxHash { + t.Fatalf("tx hash mismatch: got %s want %s", block.TxHash(), wantTxHash) + } + // Builder's UncleHash must be preserved verbatim (design principle: validator + // only computes Extra / signatures / TxHash; everything else flows from builder). + if block.UncleHash() != builderUncleHash { + t.Fatalf("uncle hash mismatch: got %s want %s", block.UncleHash(), builderUncleHash) + } + expectedHeader := types.CopyHeader(decoded.Header) + expectedHeader.Extra = common.CopyBytes(w.extra) + if err := engine.SetExtraData(chain, expectedHeader); err != nil { + t.Fatalf("SetExtraData failed: %v", err) + } + if got := block.Extra(); !bytes.Equal(got, expectedHeader.Extra) { + t.Fatalf("extra mismatch: got %x want %x", got, expectedHeader.Extra) + } +} + func TestEmptyWorkEthash(t *testing.T) { t.Parallel() testEmptyWork(t, ethashChainConfig, ethash.NewFaker()) diff --git a/node/config.go b/node/config.go index 8e18fc7d62..bc8679756a 100644 --- a/node/config.go +++ b/node/config.go @@ -104,9 +104,6 @@ type Config struct { // EnableQuickBlockFetching indicates whether to fetch new blocks using new messages. EnableQuickBlockFetching bool `toml:",omitempty"` - // EnableBAL enables the block access list feature - EnableBAL bool `toml:",omitempty"` - // RangeLimit enable 5000 blocks limit when handle range query RangeLimit bool `toml:",omitempty"` diff --git a/node/errors.go b/node/errors.go index b53f0c8083..f9188f8d99 100644 --- a/node/errors.go +++ b/node/errors.go @@ -24,10 +24,9 @@ import ( ) var ( - ErrDatadirUsed = errors.New("datadir already used by another process") - ErrNodeStopped = errors.New("node not started") - ErrNodeRunning = errors.New("node already running") - ErrSeprateDBDatadir = errors.New("datadir is not configured when using separate trie") + ErrDatadirUsed = errors.New("datadir already used by another process") + ErrNodeStopped = errors.New("node not started") + ErrNodeRunning = errors.New("node already running") datadirInUseErrnos = map[uint]bool{11: true, 32: true, 35: true} ) diff --git a/node/node.go b/node/node.go index 573a5f315a..2287d42033 100644 --- a/node/node.go +++ b/node/node.go @@ -34,7 +34,6 @@ import ( "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/common/hexutil" "github.com/ethereum/go-ethereum/core/rawdb" - "github.com/ethereum/go-ethereum/eth/ethconfig" "github.com/ethereum/go-ethereum/ethdb" "github.com/ethereum/go-ethereum/ethdb/memorydb" "github.com/ethereum/go-ethereum/event" @@ -75,12 +74,8 @@ const ( initializingState = iota runningState closedState - chainDbMemoryPercentage = 50 - chainDbHandlesPercentage = 50 ) -const StateDBNamespace = "eth/db/statedata/" - // New creates a new P2P node, ready for protocol registration. func New(conf *Config) (*Node, error) { // Copy config and resolve the datadir so future changes to the current @@ -782,47 +777,6 @@ func (n *Node) OpenDatabase(name string, cache, handles int, namespace string, r }) } -func (n *Node) OpenAndMergeDatabase(name string, namespace string, readonly bool, config *ethconfig.Config) (ethdb.Database, error) { - var ( - err error - stateDiskDb ethdb.Database - chainDataHandles = config.DatabaseHandles - chainDbCache = config.DatabaseCache - stateDbCache, stateDbHandles int - ) - - isMultiDatabase := n.CheckIfMultiDataBase() - // Open the separated state database if the state directory exists - if isMultiDatabase { - // Resource allocation rules: - // 1) Allocate a fixed percentage of memory for chainDb based on chainDbMemoryPercentage & chainDbHandlesPercentage. - // 2) Allocate the remaining resources to stateDb. - chainDbCache = int(float64(config.DatabaseCache) * chainDbMemoryPercentage / 100) - chainDataHandles = int(float64(config.DatabaseHandles) * chainDbHandlesPercentage / 100) - - stateDbCache = config.DatabaseCache - chainDbCache - stateDbHandles = config.DatabaseHandles - chainDataHandles - } - - chainDB, err := n.OpenDatabaseWithFreezer(name, chainDbCache, chainDataHandles, config.DatabaseFreezer, namespace, readonly) - if err != nil { - return nil, err - } - - if isMultiDatabase { - // Allocate half of the handles and chainDbCache to this separate state data database - stateDiskDb, err = n.OpenDatabaseWithFreezer(name+"/state", stateDbCache, stateDbHandles, "", "eth/db/statedata/", readonly) - if err != nil { - return nil, err - } - - log.Warn("Multi-database is an experimental feature") - chainDB.SetStateStore(stateDiskDb) - } - - return chainDB, nil -} - // OpenDatabaseWithFreezer opens an existing database with the given name (or // creates one if no previous can be found) from within the node's data directory. // If the node has no data directory, an in-memory database is returned. @@ -837,19 +791,6 @@ func (n *Node) OpenDatabaseWithFreezer(name string, cache, handles int, ancient }) } -// CheckIfMultiDataBase check the state and block subdirectory of db, if subdirectory exists, return true -func (n *Node) CheckIfMultiDataBase() bool { - stateExist := true - - separateStateDir := filepath.Join(n.ResolvePath("chaindata"), "state") - fileInfo, stateErr := os.Stat(separateStateDir) - if os.IsNotExist(stateErr) || !fileInfo.IsDir() { - stateExist = false - } - - return stateExist -} - // ResolvePath returns the absolute path of a resource in the instance directory. func (n *Node) ResolvePath(x string) string { return n.config.ResolvePath(x) diff --git a/p2p/discover/table.go b/p2p/discover/table.go index 14dcb8fe3c..dade4c36da 100644 --- a/p2p/discover/table.go +++ b/p2p/discover/table.go @@ -764,6 +764,41 @@ func (tab *Table) deleteNode(n *enode.Node) { // waitForNodes blocks until the table contains at least n nodes. func (tab *Table) waitForNodes(ctx context.Context, n int) error { + // Wrap ctx so the forwarder goroutine exits when waitForNodes returns, + // regardless of whether the caller's ctx is canceled. + ctx, cancel := context.WithCancel(ctx) + defer cancel() + + // Set up a notification channel that gets unblocked when there was any activity on + // the table. Ultimately this reads from the table's nodeFeed, but can't use the feed + // directly on the same goroutine that takes Table.mutex, it would deadlock. + var notify chan struct{} + var notifyErr error + initsub := func() event.Subscription { + notify = make(chan struct{}, 1) + newnode := make(chan *enode.Node, 1) + sub := tab.nodeFeed.Subscribe(newnode) + go func() { + defer close(notify) + for { + select { + case <-newnode: + select { + case notify <- struct{}{}: + default: + } + case <-ctx.Done(): + notifyErr = ctx.Err() + return + case <-tab.closeReq: + notifyErr = errClosed + return + } + } + }() + return sub + } + getlength := func() (count int) { for _, b := range &tab.buckets { count += len(b.entries) @@ -771,28 +806,24 @@ func (tab *Table) waitForNodes(ctx context.Context, n int) error { return count } - var ch chan *enode.Node for { tab.mutex.Lock() if getlength() >= n { tab.mutex.Unlock() return nil } - if ch == nil { - // Init subscription. - ch = make(chan *enode.Node) - sub := tab.nodeFeed.Subscribe(ch) + if notify == nil { + // Lazily init the subscription. Do this while holding the + // lock so we don't miss any events that change the node count. + sub := initsub() defer sub.Unsubscribe() } tab.mutex.Unlock() - // Wait for a node add event. - select { - case <-ch: - case <-ctx.Done(): - return ctx.Err() - case <-tab.closeReq: - return errClosed + // Wait for table event. + if _, ok := <-notify; !ok { + break } } + return notifyErr } diff --git a/p2p/discover/table_test.go b/p2p/discover/table_test.go index ae981f8b28..1e7881423e 100644 --- a/p2p/discover/table_test.go +++ b/p2p/discover/table_test.go @@ -17,6 +17,7 @@ package discover import ( + "context" "crypto/ecdsa" "fmt" "math/rand" @@ -529,6 +530,45 @@ func quickcfg() *quick.Config { } } +// This test checks that waitForNodes does not block addFoundNode. +// See https://github.com/ethereum/go-ethereum/issues/34881. +func TestTable_waitForNodesLocking(t *testing.T) { + transport := newPingRecorder() + tab, db := newTestTable(transport, Config{}) + defer db.Close() + defer tab.close() + <-tab.initDone + + // waitForNodes will never reach this count, so it stays subscribed + // to nodeFeed and looping for the duration of the test. + waitCtx, cancelWait := context.WithCancel(context.Background()) + defer cancelWait() + waitDone := make(chan struct{}) + go func() { + defer close(waitDone) + tab.waitForNodes(waitCtx, 1<<20) + }() + + // Call addFoundNode in loop to send to the feed. + addDone := make(chan struct{}) + go func() { + defer close(addDone) + for i := range 10000 { + d := 240 + (i % 17) + n := nodeAtDistance(tab.self().ID(), d, intIP(i)) + tab.addFoundNode(n, true) + } + }() + + select { + case <-addDone: + cancelWait() + <-waitDone + case <-time.After(10 * time.Second): + t.Fatal("deadlock detected: add loop did not finish within 10s") + } +} + func newkey() *ecdsa.PrivateKey { key, err := crypto.GenerateKey() if err != nil { diff --git a/p2p/discover/v4_udp.go b/p2p/discover/v4_udp.go index 67387b6294..f080cc7ece 100644 --- a/p2p/discover/v4_udp.go +++ b/p2p/discover/v4_udp.go @@ -448,7 +448,8 @@ func (t *UDPv4) loop(isBootNode bool) { } // Start the timer so it fires when the next pending reply has expired. now := time.Now() - for el := plist.Front(); el != nil; el = el.Next() { + for el := plist.Front(); el != nil; { + next := el.Next() nextTimeout = el.Value.(*replyMatcher) if dist := nextTimeout.deadline.Sub(now); dist < 2*respTimeout { timeout.Reset(dist) @@ -459,6 +460,7 @@ func (t *UDPv4) loop(isBootNode bool) { // backwards after the deadline was assigned. nextTimeout.errc <- errClockWarp plist.Remove(el) + el = next } nextTimeout = nil timeout.Stop() @@ -486,7 +488,8 @@ func (t *UDPv4) loop(isBootNode bool) { case r := <-t.gotreply: var matched bool // whether any replyMatcher considered the reply acceptable. - for el := plist.Front(); el != nil; el = el.Next() { + for el := plist.Front(); el != nil; { + next := el.Next() p := el.Value.(*replyMatcher) if p.from == r.from && p.ptype == r.data.Kind() && p.ip == r.ip { ok, requestDone := p.callback(r.data) @@ -500,6 +503,7 @@ func (t *UDPv4) loop(isBootNode bool) { // Reset the continuous timeout counter (time drift detection) contTimeouts = 0 } + el = next } r.matched <- matched @@ -507,13 +511,15 @@ func (t *UDPv4) loop(isBootNode bool) { nextTimeout = nil // Notify and remove callbacks whose deadline is in the past. - for el := plist.Front(); el != nil; el = el.Next() { + for el := plist.Front(); el != nil; { + next := el.Next() p := el.Value.(*replyMatcher) if now.After(p.deadline) || now.Equal(p.deadline) { p.errc <- errTimeout plist.Remove(el) contTimeouts++ } + el = next } // If we've accumulated too many timeouts, do an NTP time sync check if contTimeouts > ntpFailureThreshold { @@ -570,8 +576,9 @@ func (t *UDPv4) readLoop(unhandled chan<- ReadPacket) { if err := t.handlePacket(from, buf[:nbytes]); err != nil && unhandled == nil { t.log.Debug("Bad discv4 packet", "addr", from, "err", err) } else if err != nil && unhandled != nil { + p := ReadPacket{bytes.Clone(buf[:nbytes]), from} select { - case unhandled <- ReadPacket{buf[:nbytes], from}: + case unhandled <- p: default: } } diff --git a/p2p/peer.go b/p2p/peer.go index e3362bfc85..4c9726f78f 100644 --- a/p2p/peer.go +++ b/p2p/peer.go @@ -132,9 +132,6 @@ type Peer struct { // Indicates whether this peer is proxyed. ProxyedPeerFlag atomic.Bool - - // it indicates the peer can handle BAL(block access list) packet - CanHandleBAL atomic.Bool } // NewPeer returns a peer for testing purposes. diff --git a/params/config.go b/params/config.go index 8e9b40398a..5b9a7166f7 100644 --- a/params/config.go +++ b/params/config.go @@ -252,10 +252,10 @@ var ( FermiTime: newUint64(1768357800), // 2026-01-14 02:30:00 AM UTC OsakaTime: newUint64(1777343400), // 2026-04-28 02:30:00 AM UTC MendelTime: newUint64(1777343400), // 2026-04-28 02:30:00 AM UTC - BPO1Time: nil, // will be skipped in BSC - BPO2Time: nil, // will be skipped in BSC - AmsterdamTime: nil, PasteurTime: nil, + BPO1Time: nil, // will be skipped in BSC + BPO2Time: nil, // will be skipped in BSC + AmsterdamTime: nil, Parlia: &ParliaConfig{}, BlobScheduleConfig: &BlobScheduleConfig{ @@ -306,10 +306,10 @@ var ( FermiTime: newUint64(1762741500), // 2025-11-10 02:25:00 AM UTC OsakaTime: newUint64(1774319400), // 2026-03-24 02:30:00 AM UTC MendelTime: newUint64(1774319400), // 2026-03-24 02:30:00 AM UTC - BPO1Time: nil, // will be skipped in BSC - BPO2Time: nil, // will be skipped in BSC - AmsterdamTime: nil, PasteurTime: nil, + BPO1Time: nil, // will be skipped in BSC + BPO2Time: nil, // will be skipped in BSC + AmsterdamTime: nil, Parlia: &ParliaConfig{}, BlobScheduleConfig: &BlobScheduleConfig{ @@ -362,10 +362,10 @@ var ( // TODO: set them to `0` when passed on the mainnet OsakaTime: nil, MendelTime: nil, + PasteurTime: nil, BPO1Time: nil, // will be skipped in BSC BPO2Time: nil, // will be skipped in BSC AmsterdamTime: nil, - PasteurTime: nil, Parlia: &ParliaConfig{}, BlobScheduleConfig: &BlobScheduleConfig{ @@ -722,13 +722,13 @@ type ChainConfig struct { FermiTime *uint64 `json:"fermiTime,omitempty"` // Fermi switch time (nil = no fork, 0 = already on fermi) OsakaTime *uint64 `json:"osakaTime,omitempty"` // Osaka switch time (nil = no fork, 0 = already on osaka) MendelTime *uint64 `json:"mendelTime,omitempty"` // Mendel switch time (nil = no fork, 0 = already on mendel) + PasteurTime *uint64 `json:"pasteurTime,omitempty"` // Pasteur switch time (nil = no fork, 0 = already on pasteur) BPO1Time *uint64 `json:"bpo1Time,omitempty"` // BPO1 switch time (nil = no fork, 0 = already on bpo1) BPO2Time *uint64 `json:"bpo2Time,omitempty"` // BPO2 switch time (nil = no fork, 0 = already on bpo2) BPO3Time *uint64 `json:"bpo3Time,omitempty"` // BPO3 switch time (nil = no fork, 0 = already on bpo3) BPO4Time *uint64 `json:"bpo4Time,omitempty"` // BPO4 switch time (nil = no fork, 0 = already on bpo4) BPO5Time *uint64 `json:"bpo5Time,omitempty"` // BPO5 switch time (nil = no fork, 0 = already on bpo5) AmsterdamTime *uint64 `json:"amsterdamTime,omitempty"` // Amsterdam switch time (nil = no fork, 0 = already on amsterdam) - PasteurTime *uint64 `json:"pasteurTime,omitempty"` // PasteurTime switch time (nil = no fork, 0 = already on pasteurTime) VerkleTime *uint64 `json:"verkleTime,omitempty"` // Verkle switch time (nil = no fork, 0 = already on verkle) // TerminalTotalDifficulty is the amount of total difficulty reached by @@ -915,6 +915,11 @@ func (c *ChainConfig) String() string { MendelTime = big.NewInt(0).SetUint64(*c.MendelTime) } + var PasteurTime *big.Int + if c.PasteurTime != nil { + PasteurTime = big.NewInt(0).SetUint64(*c.PasteurTime) + } + var BPO1Time *big.Int if c.BPO1Time != nil { BPO1Time = big.NewInt(0).SetUint64(*c.BPO1Time) @@ -925,15 +930,10 @@ func (c *ChainConfig) String() string { BPO2Time = big.NewInt(0).SetUint64(*c.BPO2Time) } - var PasteurTime *big.Int - if c.PasteurTime != nil { - PasteurTime = big.NewInt(0).SetUint64(*c.PasteurTime) - } - return fmt.Sprintf("{ChainID: %v, Engine: %v, Homestead: %v DAO: %v DAOSupport: %v EIP150: %v EIP155: %v EIP158: %v Byzantium: %v Constantinople: %v Petersburg: %v Istanbul: %v, Muir Glacier: %v, Ramanujan: %v, Niels: %v, "+ "MirrorSync: %v, Bruno: %v, Berlin: %v, YOLO v3: %v, CatalystBlock: %v, London: %v, ArrowGlacier: %v, MergeFork:%v, Euler: %v, Gibbs: %v, Nano: %v, Moran: %v, Planck: %v,Luban: %v, Plato: %v, Hertz: %v, Hertzfix: %v, "+ "ShanghaiTime: %v, KeplerTime: %v, FeynmanTime: %v, FeynmanFixTime: %v, CancunTime: %v, HaberTime: %v, HaberFixTime: %v, BohrTime: %v, PascalTime: %v, PragueTime: %v, LorentzTime: %v, MaxwellTime: %v, FermiTime: %v, "+ - "OsakaTime: %v, MendelTime: %v, BPO1Time: %v, BPO2Time: %v, PasteurTime: %v}", + "OsakaTime: %v, MendelTime: %v, PasteurTime: %v, BPO1Time: %v, BPO2Time: %v}", c.ChainID, engine, c.HomesteadBlock, @@ -981,9 +981,9 @@ func (c *ChainConfig) String() string { FermiTime, OsakaTime, MendelTime, + PasteurTime, BPO1Time, BPO2Time, - PasteurTime, ) } @@ -1444,6 +1444,20 @@ func (c *ChainConfig) IsOnMendel(currentBlockNumber *big.Int, lastBlockTime uint return !c.IsMendel(lastBlockNumber, lastBlockTime) && c.IsMendel(currentBlockNumber, currentBlockTime) } +// IsPasteur returns whether time is either equal to the Pasteur fork time or greater. +func (c *ChainConfig) IsPasteur(num *big.Int, time uint64) bool { + return c.IsLondon(num) && isTimestampForked(c.PasteurTime, time) +} + +// IsOnPasteur eturns whether currentBlockTime is either equal to the Pasteur fork time or greater firstly. +func (c *ChainConfig) IsOnPasteur(currentBlockNumber *big.Int, lastBlockTime uint64, currentBlockTime uint64) bool { + lastBlockNumber := new(big.Int) + if currentBlockNumber.Cmp(big.NewInt(1)) >= 0 { + lastBlockNumber.Sub(currentBlockNumber, big.NewInt(1)) + } + return !c.IsPasteur(lastBlockNumber, lastBlockTime) && c.IsPasteur(currentBlockNumber, currentBlockTime) +} + // IsBPO1 returns whether time is either equal to the BPO1 fork time or greater. func (c *ChainConfig) IsBPO1(num *big.Int, time uint64) bool { return c.IsLondon(num) && isTimestampForked(c.BPO1Time, time) @@ -1474,20 +1488,6 @@ func (c *ChainConfig) IsAmsterdam(num *big.Int, time uint64) bool { return c.IsLondon(num) && isTimestampForked(c.AmsterdamTime, time) } -// IsPasteur returns whether time is either equal to the Pasteur fork time or greater. -func (c *ChainConfig) IsPasteur(num *big.Int, time uint64) bool { - return c.IsLondon(num) && isTimestampForked(c.PasteurTime, time) -} - -// IsOnPasteur eturns whether currentBlockTime is either equal to the Pasteur fork time or greater firstly. -func (c *ChainConfig) IsOnPasteur(currentBlockNumber *big.Int, lastBlockTime uint64, currentBlockTime uint64) bool { - lastBlockNumber := new(big.Int) - if currentBlockNumber.Cmp(big.NewInt(1)) >= 0 { - lastBlockNumber.Sub(currentBlockNumber, big.NewInt(1)) - } - return !c.IsPasteur(lastBlockNumber, lastBlockTime) && c.IsPasteur(currentBlockNumber, currentBlockTime) -} - // IsVerkle returns whether time is either equal to the Verkle fork time or greater. func (c *ChainConfig) IsVerkle(num *big.Int, time uint64) bool { return c.IsLondon(num) && isTimestampForked(c.VerkleTime, time) @@ -1575,6 +1575,7 @@ func (c *ChainConfig) CheckConfigForkOrder() error { {name: "fermiTime", timestamp: c.FermiTime}, {name: "osakaTime", timestamp: c.OsakaTime}, {name: "mendelTime", timestamp: c.MendelTime}, + {name: "pasteurTime", timestamp: c.PasteurTime}, {name: "verkleTime", timestamp: c.VerkleTime, optional: true}, {name: "bpo1", timestamp: c.BPO1Time, optional: true}, {name: "bpo2", timestamp: c.BPO2Time, optional: true}, @@ -1582,7 +1583,6 @@ func (c *ChainConfig) CheckConfigForkOrder() error { {name: "bpo4", timestamp: c.BPO4Time, optional: true}, {name: "bpo5", timestamp: c.BPO5Time, optional: true}, {name: "amsterdam", timestamp: c.AmsterdamTime, optional: true}, - {name: "pasteurTime", timestamp: c.PasteurTime, optional: true}, } { if lastFork.name != "" { switch { @@ -1804,6 +1804,9 @@ func (c *ChainConfig) checkCompatible(newcfg *ChainConfig, headNumber *big.Int, if isForkTimestampIncompatible(c.MendelTime, newcfg.MendelTime, headTimestamp) { return newTimestampCompatError("Mendel fork timestamp", c.MendelTime, newcfg.MendelTime) } + if isForkTimestampIncompatible(c.PasteurTime, newcfg.PasteurTime, headTimestamp) { + return newTimestampCompatError("Pasteur fork timestamp", c.PasteurTime, newcfg.PasteurTime) + } if isForkTimestampIncompatible(c.VerkleTime, newcfg.VerkleTime, headTimestamp) { return newTimestampCompatError("Verkle fork timestamp", c.VerkleTime, newcfg.VerkleTime) } @@ -1825,9 +1828,6 @@ func (c *ChainConfig) checkCompatible(newcfg *ChainConfig, headNumber *big.Int, if isForkTimestampIncompatible(c.AmsterdamTime, newcfg.AmsterdamTime, headTimestamp) { return newTimestampCompatError("Amsterdam fork timestamp", c.AmsterdamTime, newcfg.AmsterdamTime) } - if isForkTimestampIncompatible(c.PasteurTime, newcfg.PasteurTime, headTimestamp) { - return newTimestampCompatError("Pasteur fork timestamp", c.PasteurTime, newcfg.PasteurTime) - } return nil } @@ -1848,8 +1848,6 @@ func (c *ChainConfig) LatestFork(time uint64) forks.Fork { london := c.LondonBlock switch { - case c.IsPasteur(london, time): - return forks.Pasteur case c.IsAmsterdam(london, time): return forks.Amsterdam case c.IsBPO5(london, time): @@ -1862,6 +1860,8 @@ func (c *ChainConfig) LatestFork(time uint64) forks.Fork { return forks.BPO2 case c.IsBPO1(london, time): return forks.BPO1 + case c.IsPasteur(london, time): + return forks.Pasteur case c.IsMendel(london, time): return forks.Mendel case c.IsOsaka(london, time): @@ -1937,8 +1937,6 @@ func (c *ChainConfig) ActiveSystemContracts(time uint64) map[string]common.Addre // the fork isn't defined or isn't a time-based fork. func (c *ChainConfig) Timestamp(fork forks.Fork) *uint64 { switch { - case fork == forks.Pasteur: - return c.PasteurTime case fork == forks.Amsterdam: return c.AmsterdamTime case fork == forks.BPO5: @@ -1951,6 +1949,8 @@ func (c *ChainConfig) Timestamp(fork forks.Fork) *uint64 { return c.BPO2Time case fork == forks.BPO1: return c.BPO1Time + case fork == forks.Pasteur: + return c.PasteurTime case fork == forks.Mendel: return c.MendelTime case fork == forks.Osaka: @@ -2123,7 +2123,7 @@ type Rules struct { IsShanghai, IsKepler, IsFeynman, IsCancun, IsHaber bool IsBohr, IsPascal, IsPrague, IsLorentz, IsMaxwell bool IsFermi, IsOsaka, IsMendel bool - IsAmsterdam, IsPasteur, IsVerkle bool + IsPasteur, IsAmsterdam, IsVerkle bool } // Rules ensures c's ChainID is not nil. @@ -2169,8 +2169,8 @@ func (c *ChainConfig) Rules(num *big.Int, isMerge bool, timestamp uint64) Rules IsFermi: c.IsFermi(num, timestamp), IsOsaka: (isMerge || c.IsInBSC()) && c.IsOsaka(num, timestamp), IsMendel: c.IsMendel(num, timestamp), - IsAmsterdam: (isMerge || c.IsInBSC()) && c.IsAmsterdam(num, timestamp), IsPasteur: c.IsPasteur(num, timestamp), + IsAmsterdam: (isMerge || c.IsInBSC()) && c.IsAmsterdam(num, timestamp), IsVerkle: c.IsVerkle(num, timestamp), IsEIP4762: isVerkle, } diff --git a/params/forks/forks.go b/params/forks/forks.go index cc35fd5d3a..bc7c8e9ecc 100644 --- a/params/forks/forks.go +++ b/params/forks/forks.go @@ -45,7 +45,7 @@ const ( Fermi Osaka Mendel - Pasteur // BOP1 will be skipped in BSC, so let Pasteur be the next to Mendel + Pasteur BPO1 BPO2 BPO3 @@ -88,11 +88,11 @@ var forkToString = map[Fork]string{ Fermi: "Fermi", Osaka: "Osaka", Mendel: "Mendel", + Pasteur: "Pasteur", BPO1: "BPO1", BPO2: "BPO2", BPO3: "BPO3", BPO4: "BPO4", BPO5: "BPO5", Amsterdam: "Amsterdam", - Pasteur: "Pasteur", } diff --git a/params/network_params.go b/params/network_params.go index ae5ca01c2d..5881cf3e22 100644 --- a/params/network_params.go +++ b/params/network_params.go @@ -22,9 +22,6 @@ package params const ( // StableStateThreshold is the reserve number of block state save to disk before delete ancientdb StableStateThreshold uint64 = 128 - - // MaxBALSize is the maximum bytes of the rlp encoded block access list: 1MB - MaxBALSize uint64 = 1048576 ) var ( diff --git a/params/protocol_params.go b/params/protocol_params.go index d41af34e81..ec68d95fa8 100644 --- a/params/protocol_params.go +++ b/params/protocol_params.go @@ -27,7 +27,7 @@ const ( 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. - PayBidTxGasLimit uint64 = 25000 // Gas limit of the PayBidTx in the types.BidArgs. + PayBidTxGasLimit uint64 = 25000 // Gas limit of the PayBidTx in the builder.BidArgs. MaxTxGas uint64 = 1 << 24 // Maximum transaction gas limit after eip-7825 (16,777,216). MaximumExtraDataSize uint64 = 32 // Maximum size extra data may be after Genesis. @@ -143,9 +143,10 @@ const ( // Precompiled contract gas prices - TendermintHeaderValidateGas uint64 = 3000 // Gas for validate tendermiint consensus state - IAVLMerkleProofValidateGas uint64 = 3000 // Gas for validate merkle proof - CometBFTLightBlockValidateGas uint64 = 3000 // Gas for validate cometBFT light block + TendermintHeaderValidateGas uint64 = 3000 // Gas for validate tendermiint consensus state + IAVLMerkleProofValidateGas uint64 = 3000 // Gas for validate merkle proof + CometBFTLightBlockValidateGas uint64 = 3000 // Base gas for validate cometBFT light block + CometBFTLightBlockValidatePerByteGas uint64 = 16 // Per-input-byte gas for cometBFT light block (Pasteur) EcrecoverGas uint64 = 3000 // Elliptic curve sender recovery gas price Sha256BaseGas uint64 = 60 // Base price for a SHA256 operation diff --git a/tests/block_test_util.go b/tests/block_test_util.go index bd9639474c..2bcaaca16a 100644 --- a/tests/block_test_util.go +++ b/tests/block_test_util.go @@ -158,9 +158,9 @@ func (t *BlockTest) Run(snapshotter bool, scheme string, witness bool, tracer *t Preimages: true, TxLookupLimit: -1, // disable tx indexing VmConfig: vm.Config{ - Tracer: tracer, - StatelessSelfValidation: witness, + Tracer: tracer, }, + StatelessSelfValidation: witness, } if snapshotter { options.SnapshotLimit = 1 diff --git a/trie/sync.go b/trie/sync.go index 001eae7b39..8272b980e9 100644 --- a/trie/sync.go +++ b/trie/sync.go @@ -451,7 +451,7 @@ func (s *Sync) ProcessNode(result NodeSyncResult) error { // Commit flushes the data stored in the internal membatch out to persistent // storage, returning any occurred error. The whole data set will be flushed // in an atomic database batch. -func (s *Sync) Commit(dbw ethdb.Batch, stateBatch ethdb.Batch) error { +func (s *Sync) Commit(dbw ethdb.Batch) error { // Flush the pending node writes into database batch. var ( account int @@ -464,17 +464,9 @@ func (s *Sync) Commit(dbw ethdb.Batch, stateBatch ethdb.Batch) error { if op.del { // node deletion is only supported in path mode. if op.owner == (common.Hash{}) { - if stateBatch != nil { - rawdb.DeleteAccountTrieNode(stateBatch, op.path) - } else { - rawdb.DeleteAccountTrieNode(dbw, op.path) - } + rawdb.DeleteAccountTrieNode(dbw, op.path) } else { - if stateBatch != nil { - rawdb.DeleteStorageTrieNode(stateBatch, op.owner, op.path) - } else { - rawdb.DeleteStorageTrieNode(dbw, op.owner, op.path) - } + rawdb.DeleteStorageTrieNode(dbw, op.owner, op.path) } deletionGauge.Inc(1) } else { @@ -483,11 +475,7 @@ func (s *Sync) Commit(dbw ethdb.Batch, stateBatch ethdb.Batch) error { } else { storage += 1 } - if stateBatch != nil { - rawdb.WriteTrieNode(stateBatch, op.owner, op.path, op.hash, op.blob, s.scheme) - } else { - rawdb.WriteTrieNode(dbw, op.owner, op.path, op.hash, op.blob, s.scheme) - } + rawdb.WriteTrieNode(dbw, op.owner, op.path, op.hash, op.blob, s.scheme) } } accountNodeSyncedGauge.Inc(int64(account)) @@ -592,9 +580,9 @@ func (s *Sync) children(req *nodeRequest, object node) ([]*nodeRequest, error) { // the performance impact negligible. var exists bool if owner == (common.Hash{}) { - exists = rawdb.HasAccountTrieNode(s.database.StateStoreReader(), append(inner, key[:i]...)) + exists = rawdb.HasAccountTrieNode(s.database, append(inner, key[:i]...)) } else { - exists = rawdb.HasStorageTrieNode(s.database.StateStoreReader(), owner, append(inner, key[:i]...)) + exists = rawdb.HasStorageTrieNode(s.database, owner, append(inner, key[:i]...)) } if exists { s.membatch.delNode(owner, append(inner, key[:i]...)) @@ -733,14 +721,14 @@ func (s *Sync) commitCodeRequest(req *codeRequest) error { func (s *Sync) hasNode(owner common.Hash, path []byte, hash common.Hash) (exists bool, inconsistent bool) { // If node is running with hash scheme, check the presence with node hash. if s.scheme == rawdb.HashScheme { - return rawdb.HasLegacyTrieNode(s.database.StateStoreReader(), hash), false + return rawdb.HasLegacyTrieNode(s.database, hash), false } // If node is running with path scheme, check the presence with node path. var blob []byte if owner == (common.Hash{}) { - blob = rawdb.ReadAccountTrieNode(s.database.StateStoreReader(), path) + blob = rawdb.ReadAccountTrieNode(s.database, path) } else { - blob = rawdb.ReadStorageTrieNode(s.database.StateStoreReader(), owner, path) + blob = rawdb.ReadStorageTrieNode(s.database, owner, path) } exists = hash == crypto.Keccak256Hash(blob) inconsistent = !exists && len(blob) != 0 diff --git a/trie/sync_test.go b/trie/sync_test.go index fb5fb13ff0..2a8f601414 100644 --- a/trie/sync_test.go +++ b/trie/sync_test.go @@ -212,7 +212,7 @@ func testIterativeSync(t *testing.T, count int, bypath bool, scheme string) { } } batch := diskdb.NewBatch() - if err := sched.Commit(batch, nil); err != nil { + if err := sched.Commit(batch); err != nil { t.Fatalf("failed to commit data: %v", err) } batch.Write() @@ -278,7 +278,7 @@ func testIterativeDelayedSync(t *testing.T, scheme string) { } } batch := diskdb.NewBatch() - if err := sched.Commit(batch, nil); err != nil { + if err := sched.Commit(batch); err != nil { t.Fatalf("failed to commit data: %v", err) } batch.Write() @@ -348,7 +348,7 @@ func testIterativeRandomSync(t *testing.T, count int, scheme string) { } } batch := diskdb.NewBatch() - if err := sched.Commit(batch, nil); err != nil { + if err := sched.Commit(batch); err != nil { t.Fatalf("failed to commit data: %v", err) } batch.Write() @@ -419,7 +419,7 @@ func testIterativeRandomDelayedSync(t *testing.T, scheme string) { } } batch := diskdb.NewBatch() - if err := sched.Commit(batch, nil); err != nil { + if err := sched.Commit(batch); err != nil { t.Fatalf("failed to commit data: %v", err) } batch.Write() @@ -491,7 +491,7 @@ func testDuplicateAvoidanceSync(t *testing.T, scheme string) { } } batch := diskdb.NewBatch() - if err := sched.Commit(batch, nil); err != nil { + if err := sched.Commit(batch); err != nil { t.Fatalf("failed to commit data: %v", err) } batch.Write() @@ -563,7 +563,7 @@ func testIncompleteSync(t *testing.T, scheme string) { } } batch := diskdb.NewBatch() - if err := sched.Commit(batch, nil); err != nil { + if err := sched.Commit(batch); err != nil { t.Fatalf("failed to commit data: %v", err) } batch.Write() @@ -653,7 +653,7 @@ func testSyncOrdering(t *testing.T, scheme string) { } } batch := diskdb.NewBatch() - if err := sched.Commit(batch, nil); err != nil { + if err := sched.Commit(batch); err != nil { t.Fatalf("failed to commit data: %v", err) } batch.Write() @@ -723,7 +723,7 @@ func syncWithHookWriter(t *testing.T, root common.Hash, db ethdb.Database, srcDb } } batch := db.NewBatch() - if err := sched.Commit(batch, nil); err != nil { + if err := sched.Commit(batch); err != nil { t.Fatalf("failed to commit data: %v", err) } if hookWriter != nil { diff --git a/triedb/database.go b/triedb/database.go index 2f6fd24332..4c4834f9e5 100644 --- a/triedb/database.go +++ b/triedb/database.go @@ -95,11 +95,6 @@ type Database struct { // the legacy hash-based scheme is used by default. func NewDatabase(diskdb ethdb.Database, config *Config) *Database { // Sanitize the config and use the default one if it's not specified. - var triediskdb ethdb.Database - if diskdb != nil { - triediskdb = diskdb.GetStateStore() - } - dbScheme := rawdb.ReadStateScheme(diskdb) if config == nil { if dbScheme == rawdb.PathScheme { @@ -119,7 +114,7 @@ func NewDatabase(diskdb ethdb.Database, config *Config) *Database { } var preimages *preimageStore if config.Preimages { - preimages = newPreimageStore(triediskdb) + preimages = newPreimageStore(diskdb) } db := &Database{ disk: diskdb, @@ -132,25 +127,25 @@ func NewDatabase(diskdb ethdb.Database, config *Config) *Database { * 3. Last, use the default scheme, namely hash scheme */ if config.HashDB != nil { - if rawdb.ReadStateScheme(triediskdb) == rawdb.PathScheme { + if rawdb.ReadStateScheme(diskdb) == rawdb.PathScheme { log.Warn("Incompatible state scheme", "old", rawdb.PathScheme, "new", rawdb.HashScheme) } - db.backend = hashdb.New(triediskdb, config.HashDB) + db.backend = hashdb.New(diskdb, config.HashDB) } else if config.PathDB != nil { - if rawdb.ReadStateScheme(triediskdb) == rawdb.HashScheme { + if rawdb.ReadStateScheme(diskdb) == rawdb.HashScheme { log.Warn("Incompatible state scheme", "old", rawdb.HashScheme, "new", rawdb.PathScheme) } - db.backend = pathdb.New(triediskdb, config.PathDB, config.IsVerkle) + db.backend = pathdb.New(diskdb, config.PathDB, config.IsVerkle) } else if strings.Compare(dbScheme, rawdb.PathScheme) == 0 { if config.PathDB == nil { config.PathDB = pathdb.Defaults } - db.backend = pathdb.New(triediskdb, config.PathDB, config.IsVerkle) + db.backend = pathdb.New(diskdb, config.PathDB, config.IsVerkle) } else { if config.HashDB == nil { config.HashDB = hashdb.Defaults } - db.backend = hashdb.New(triediskdb, config.HashDB) + db.backend = hashdb.New(diskdb, config.HashDB) } return db } diff --git a/triedb/pathdb/config.go b/triedb/pathdb/config.go index d7cf7a5422..afc19081ff 100644 --- a/triedb/pathdb/config.go +++ b/triedb/pathdb/config.go @@ -81,8 +81,6 @@ type Config struct { NoAsyncFlush bool // Flag whether the background buffer flushing is disabled NoAsyncGeneration bool // Flag whether the background generation is disabled - JournalFilePath string // The path of journal file - EnableIncr bool // Flag whether the freezer db stores incr block and state history MergeIncr bool // Flag to merge incr snapshots IncrHistory uint64 // Amount of block and state history stored in incr freezer db diff --git a/triedb/pathdb/journal.go b/triedb/pathdb/journal.go index 7132c3f920..a2e472bcd7 100644 --- a/triedb/pathdb/journal.go +++ b/triedb/pathdb/journal.go @@ -64,15 +64,6 @@ func (db *Database) loadJournal(diskRoot common.Hash) (layer, error) { } defer f.Close() reader = f - } else if path := db.config.JournalFilePath; path != "" && common.FileExist(path) { // TODO(Nathan): delete this branch in v1.8.x - // If a journal file is specified, read it from there - log.Info("Load database journal from file", "path", path) - f, err := os.OpenFile(path, os.O_RDONLY, 0644) - if err != nil { - return nil, fmt.Errorf("failed to read journal file %s: %w", path, err) - } - defer f.Close() - reader = f } else { log.Info("Load database journal from disk") journal := rawdb.ReadTrieJournal(db.diskdb) @@ -189,40 +180,19 @@ func (db *Database) loadLayers() layer { return newDiskLayer(root, rawdb.ReadPersistentStateID(db.diskdb), db, nil, nil, newBuffer(db.config.WriteBufferSize, nil, nil, 0), nil) } -// tryUnwrapJournal detects legacy format and unwraps if needed. -// Legacy format: wraps layer data in []byte with shasum. -func tryUnwrapJournal(r *rlp.Stream) (jr *rlp.Stream, isLegacy bool, err error) { - kind, size, err := r.Kind() - if err != nil { - return nil, false, err - } - if kind == rlp.String && size > common.HashLength { - var buf []byte - if err := r.Decode(&buf); err != nil { - return nil, false, err - } - return rlp.NewStream(bytes.NewReader(buf), 0), true, nil - } - return r, false, nil -} - // loadDiskLayer reads the binary blob from the layer journal, reconstructing // a new disk layer on it. func (db *Database) loadDiskLayer(r *rlp.Stream) (layer, error) { - jr, isLegacy, err := tryUnwrapJournal(r) - if err != nil { - return nil, fmt.Errorf("load disk layer: %v", err) - } - + // Resolve disk layer root var root common.Hash - if err := jr.Decode(&root); err != nil { + if err := r.Decode(&root); err != nil { return nil, fmt.Errorf("load disk root: %v", err) } // Resolve the state id of disk layer, it can be different // with the persistent id tracked in disk, the id distance // is the number of transitions aggregated in disk layer. var id uint64 - if err := jr.Decode(&id); err != nil { + if err := r.Decode(&id); err != nil { return nil, fmt.Errorf("load state id: %v", err) } stored := rawdb.ReadPersistentStateID(db.diskdb) @@ -231,37 +201,23 @@ func (db *Database) loadDiskLayer(r *rlp.Stream) (layer, error) { } // Resolve nodes cached in aggregated buffer var nodes nodeSet - if err := nodes.decode(jr); err != nil { + if err := nodes.decode(r); err != nil { return nil, err } // Resolve flat state sets in aggregated buffer var states stateSet - if err := states.decode(jr); err != nil { + if err := states.decode(r); err != nil { return nil, err } - // Skip shasum if legacy format - if isLegacy { - var shaSum [32]byte - if err := r.Decode(&shaSum); err != nil { - return nil, fmt.Errorf("load disk shasum: %v", err) - } - } return newDiskLayer(root, id, db, nil, nil, newBuffer(db.config.WriteBufferSize, &nodes, &states, id-stored), nil), nil } // loadDiffLayer reads the next sections of a layer journal, reconstructing a new // diff and verifying that it can be linked to the requested parent. func (db *Database) loadDiffLayer(parent layer, r *rlp.Stream) (layer, error) { - jr, isLegacy, err := tryUnwrapJournal(r) - if err != nil { - if err == io.EOF { - return parent, nil - } - return nil, fmt.Errorf("load diff layer: %v", err) - } - + // Read the next diff journal entry var root common.Hash - if err := jr.Decode(&root); err != nil { + if err := r.Decode(&root); err != nil { // The first read may fail with EOF, marking the end of the journal if err == io.EOF { return parent, nil @@ -269,26 +225,19 @@ func (db *Database) loadDiffLayer(parent layer, r *rlp.Stream) (layer, error) { return nil, fmt.Errorf("load diff root: %v", err) } var block uint64 - if err := jr.Decode(&block); err != nil { + if err := r.Decode(&block); err != nil { return nil, fmt.Errorf("load block number: %v", err) } // Read in-memory trie nodes from journal var nodes nodeSetWithOrigin - if err := nodes.decode(jr); err != nil { + if err := nodes.decode(r); err != nil { return nil, err } // Read flat states set (with original value attached) from journal var stateSet StateSetWithOrigin - if err := stateSet.decode(jr); err != nil { + if err := stateSet.decode(r); err != nil { return nil, err } - // Skip shasum if legacy format - if isLegacy { - var shaSum [32]byte - if err := r.Decode(&shaSum); err != nil { - return nil, fmt.Errorf("load diff shasum: %v", err) - } - } return db.loadDiffLayer(newDiffLayer(parent, root, parent.stateID()+1, block, &nodes, &stateSet), r) } diff --git a/triedb/pathdb/layertree.go b/triedb/pathdb/layertree.go index 16eb204f43..b2f2bebbe9 100644 --- a/triedb/pathdb/layertree.go +++ b/triedb/pathdb/layertree.go @@ -315,8 +315,8 @@ func (tree *layerTree) lookupAccount(accountHash common.Hash, state common.Hash) tree.lock.RLock() defer tree.lock.RUnlock() - tip := tree.lookup.accountTip(accountHash, state, tree.base.root) - if tip == (common.Hash{}) { + tip, ok := tree.lookup.accountTip(accountHash, state, tree.base.root) + if !ok { return nil, fmt.Errorf("[%#x] %w", state, errSnapshotStale) } l := tree.layers[tip] @@ -333,8 +333,8 @@ func (tree *layerTree) lookupStorage(accountHash common.Hash, slotHash common.Ha tree.lock.RLock() defer tree.lock.RUnlock() - tip := tree.lookup.storageTip(accountHash, slotHash, state, tree.base.root) - if tip == (common.Hash{}) { + tip, ok := tree.lookup.storageTip(accountHash, slotHash, state, tree.base.root) + if !ok { return nil, fmt.Errorf("[%#x] %w", state, errSnapshotStale) } l := tree.layers[tip] diff --git a/triedb/pathdb/layertree_test.go b/triedb/pathdb/layertree_test.go index a74c6eb045..240ce03fce 100644 --- a/triedb/pathdb/layertree_test.go +++ b/triedb/pathdb/layertree_test.go @@ -882,3 +882,64 @@ func TestStorageLookup(t *testing.T) { } } } + +// TestLookupZeroBaseRootFallback regresses the sentinel collision in +// accountTip/storageTip when the disk layer root is itself common.Hash{} +// (a fresh verkle/bintrie database whose empty trie hashes to zero). +// Returning only common.Hash conflated the disk-layer fallback with the +// "stale" sentinel, so lookupAccount/Storage reported errSnapshotStale +// for a valid fall-through. +func TestLookupZeroBaseRootFallback(t *testing.T) { + db := New(rawdb.NewMemoryDatabase(), nil, false) + base := newDiskLayer(common.Hash{}, 0, db, nil, nil, newBuffer(0, nil, nil, 0), nil) + tr := newLayerTree(base) + + if err := tr.add(common.Hash{0x2}, common.Hash{}, 1, + NewNodeSetWithOrigin(nil, nil), + NewStateSetWithOrigin(randomAccountSet("0xa"), + randomStorageSet([]string{"0xa"}, [][]string{{"0x1"}}, nil), + nil, nil, false)); err != nil { + t.Fatalf("add first diff layer: %v", err) + } + if err := tr.add(common.Hash{0x3}, common.Hash{0x2}, 2, + NewNodeSetWithOrigin(nil, nil), + NewStateSetWithOrigin(randomAccountSet("0xb"), nil, nil, nil, false)); err != nil { + t.Fatalf("add second diff layer: %v", err) + } + + // Unknown account at HEAD: must fall through to the zero-rooted disk layer. + l, err := tr.lookupAccount(common.HexToHash("0xdead"), common.Hash{0x3}) + if err != nil { + t.Fatalf("lookupAccount fallback: unexpected error %v", err) + } + if l.rootHash() != (common.Hash{}) { + t.Errorf("lookupAccount fallback: want disk root 0, got %x", l.rootHash()) + } + + // Symmetric storage case. + l, err = tr.lookupStorage(common.HexToHash("0xdead"), common.HexToHash("0x99"), common.Hash{0x3}) + if err != nil { + t.Fatalf("lookupStorage fallback: unexpected error %v", err) + } + if l.rootHash() != (common.Hash{}) { + t.Errorf("lookupStorage fallback: want disk root 0, got %x", l.rootHash()) + } + + // Happy path still works: account 0xa was written in diff 0x2. + l, err = tr.lookupAccount(common.HexToHash("0xa"), common.Hash{0x3}) + if err != nil { + t.Fatalf("lookupAccount(known): %v", err) + } + if l.rootHash() != (common.Hash{0x2}) { + t.Errorf("lookupAccount(known): want %x, got %x", common.Hash{0x2}, l.rootHash()) + } + + // Truly stale state root must still surface errSnapshotStale, + // pinning the other half of the contract. + if _, err := tr.lookupAccount(common.HexToHash("0xa"), common.HexToHash("0xdeadbeef")); !errors.Is(err, errSnapshotStale) { + t.Errorf("lookupAccount(stale): want errSnapshotStale, got %v", err) + } + if _, err := tr.lookupStorage(common.HexToHash("0xa"), common.HexToHash("0x1"), common.HexToHash("0xdeadbeef")); !errors.Is(err, errSnapshotStale) { + t.Errorf("lookupStorage(stale): want errSnapshotStale, got %v", err) + } +} diff --git a/triedb/pathdb/lookup.go b/triedb/pathdb/lookup.go index 8b092730f8..f6b726cdea 100644 --- a/triedb/pathdb/lookup.go +++ b/triedb/pathdb/lookup.go @@ -85,12 +85,16 @@ func newLookup(head layer, descendant func(state common.Hash, ancestor common.Ha // stateID or is a descendant of it. // // If found, the account data corresponding to the supplied stateID resides -// in that layer. Otherwise, two scenarios are possible: +// in the layer identified by the returned hash (ok=true). Otherwise, +// (common.Hash{}, false) is returned to signal that the supplied stateID is +// stale. // -// (a) the account remains unmodified from the current disk layer up to the state -// layer specified by the stateID: fallback to the disk layer for data retrieval, -// (b) or the layer specified by the stateID is stale: reject the data retrieval. -func (l *lookup) accountTip(accountHash common.Hash, stateID common.Hash, base common.Hash) common.Hash { +// Note the returned hash may itself be common.Hash{} when the disk layer's +// root is zero — as is the case for a fresh verkle/bintrie database whose +// empty trie hashes to EmptyVerkleHash. Callers must therefore consult the +// boolean rather than comparing the returned hash against common.Hash{} +// directly. +func (l *lookup) accountTip(accountHash common.Hash, stateID common.Hash, base common.Hash) (common.Hash, bool) { // Traverse the mutation history from latest to oldest one. Several // scenarios are possible: // @@ -116,31 +120,26 @@ func (l *lookup) accountTip(accountHash common.Hash, stateID common.Hash, base c // containing the modified data. Otherwise, the current state may be ahead // of the requested one or belong to a different branch. if list[i] == stateID || l.descendant(stateID, list[i]) { - return list[i] + return list[i], true } } // No layer matching the stateID or its descendants was found. Use the // current disk layer as a fallback. if base == stateID || l.descendant(stateID, base) { - return base + return base, true } // The layer associated with 'stateID' is not the descendant of the current // disk layer, it's already stale, return nothing. - return common.Hash{} + return common.Hash{}, false } // storageTip traverses the layer list associated with the given account and // slot hash in reverse order to locate the first entry that either matches // the specified stateID or is a descendant of it. // -// If found, the storage data corresponding to the supplied stateID resides -// in that layer. Otherwise, two scenarios are possible: -// -// (a) the storage slot remains unmodified from the current disk layer up to -// the state layer specified by the stateID: fallback to the disk layer for -// data retrieval, (b) or the layer specified by the stateID is stale: reject -// the data retrieval. -func (l *lookup) storageTip(accountHash common.Hash, slotHash common.Hash, stateID common.Hash, base common.Hash) common.Hash { +// See accountTip for the returned-hash / ok convention — the same +// bintrie-zero-root caveat applies here. +func (l *lookup) storageTip(accountHash common.Hash, slotHash common.Hash, stateID common.Hash, base common.Hash) (common.Hash, bool) { list := l.storages[storageKey(accountHash, slotHash)] for i := len(list) - 1; i >= 0; i-- { // If the current state matches the stateID, or the requested state is a @@ -148,17 +147,17 @@ func (l *lookup) storageTip(accountHash common.Hash, slotHash common.Hash, state // containing the modified data. Otherwise, the current state may be ahead // of the requested one or belong to a different branch. if list[i] == stateID || l.descendant(stateID, list[i]) { - return list[i] + return list[i], true } } // No layer matching the stateID or its descendants was found. Use the // current disk layer as a fallback. if base == stateID || l.descendant(stateID, base) { - return base + return base, true } // The layer associated with 'stateID' is not the descendant of the current // disk layer, it's already stale, return nothing. - return common.Hash{} + return common.Hash{}, false } // addLayer traverses the state data retained in the specified diff layer and diff --git a/version/version.go b/version/version.go index c7dccff0d8..5c3307a015 100644 --- a/version/version.go +++ b/version/version.go @@ -19,6 +19,6 @@ package version const ( Major = 1 // Major version component of the current release Minor = 7 // Minor version component of the current release - Patch = 5 // Patch version component of the current release + Patch = 6 // Patch version component of the current release Meta = "" // Version metadata to append to the version string )