mirror of
https://github.com/ethereum/go-ethereum.git
synced 2026-07-27 23:26:44 +00:00
Merge master to qa (#813)
* Merge qa to master (#750) * Added checks to RPC requests and introduced new flags to customise the parameters (#657) * added a check to reject rpc requests with batch size > the one set using a newly added flag (rpcbatchlimit) * added a check to reject rpc requests whose result size > the one set using a newly added flag (rpcreturndatalimit) * updated the config files and docs * chg : trieTimeout from 60 to 10 mins (#692) * chg : trieTimeout from 60 to 10 mins * chg : cache.timout to 10m from 1h in configs * internal/cli/server : fix : added triesInMemory in config (#691) * changed version from 0.3.0 to 0.3.4-beta (#693) * fix nil state-sync issue, increase grpc limit (#695) * Increase grpc message size limit in pprof * consensus/bor/bor.go : stateSyncs init fixed [Fix #686] * eth/filters: handle nil state-sync before notify * eth/filters: update check Co-authored-by: Jerry <jerrycgh@gmail.com> Co-authored-by: Daniil <daniil.melnik@chainstack.com> * core, tests/bor: add more tests for state-sync validation (#710) * core: add get state sync function for tests * tests/bor: add validation for state sync events post consensus * Arpit/temp bor sync (#701) * Increase grpc message size limit in pprof * ReadBorReceipts improvements * use internal function * fix tests * fetch geth upstread for ReadBorReceiptRLP * Only query bor receipt when the query index is equal to # tx in block body This change reduces the frequency of calling ReadBorReceipt and ReadBorTransaction, which are CPU and db intensive. * Revert "fetch geth upstread for ReadBorReceiptRLP" This reverts commit 2e838a6b1313d26674f3a8df4b044e35dcbf35a0. * Restore ReadBorReceiptRLP * fix bor receipts * remove unused * fix lints --------- Co-authored-by: Jerry <jerrycgh@gmail.com> Co-authored-by: Manav Darji <manavdarji.india@gmail.com> Co-authored-by: Evgeny Danienko <6655321@bk.ru> * Revert "chg : trieTimeout from 60 to 10 mins (#692)" (#720) This reverts commit241843c7e7. * Arpit/add execution pool 2 (#719) * initial * linters * linters * remove timeout * update pool * change pool size function * check nil * check nil * fix tests * Use execution pool from server in all handlers * simplify things * test fix * add support for cli, config * add to cli and config * merge base branch * debug statements * fix bug * atomic pointer timeout * add apis * update workerpool * fix issues * change params * fix issues * fix ipc issue * remove execution pool from IPC * revert * fix tests * mutex * refactor flag and value names * ordering fix * refactor flag and value names * update default ep size to 40 * fix bor start issues * revert file changes * debug statements * fix bug * update workerpool * atomic pointer timeout * add apis * Merge branch 'add-execution-pool' of github.com:maticnetwork/bor into arpit/add-execution-pool * fix issues * change params * fix issues * fix ipc issue * remove execution pool from IPC * revert * merge base branch * Merge branch 'add-execution-pool' of github.com:maticnetwork/bor into arpit/add-execution-pool * mutex * fix tests * Merge branch 'arpit/add-execution-pool' of github.com:maticnetwork/bor into arpit/add-execution-pool * Change default size of execution pool to 40 * refactor flag and value names * fix merge conflicts * ordering fix * refactor flag and value names * update default ep size to 40 * fix bor start issues * revert file changes * fix linters * fix go.mod * change sec to ms * change default value for ep timeout * fix node api calls * comment setter for ep timeout --------- Co-authored-by: Evgeny Danienko <6655321@bk.ru> Co-authored-by: Jerry <jerrycgh@gmail.com> Co-authored-by: Manav Darji <manavdarji.india@gmail.com> * version change (#721) * Event based pprof (#732) * feature * Save pprof to /tmp --------- Co-authored-by: Jerry <jerrycgh@gmail.com> * Cherry-pick changes from develop (#738) * Check if block is nil to prevent panic (#736) * miner: use env for tracing instead of block object (#728) --------- Co-authored-by: Dmitry <46797839+dkeysil@users.noreply.github.com> * add max code init size check in txpool (#739) * Revert "Event based pprof" and update version (#742) * Revert "Event based pprof (#732)" This reverts commit22fa4033e8. * params: update version to 0.3.4-beta3 * packaging/templates: update bor version * params, packaging/templates: update bor version --------- Co-authored-by: SHIVAM SHARMA <shivam691999@gmail.com> Co-authored-by: Pratik Patil <pratikspatil024@gmail.com> Co-authored-by: Jerry <jerrycgh@gmail.com> Co-authored-by: Daniil <daniil.melnik@chainstack.com> Co-authored-by: Arpit Temani <temaniarpit27@gmail.com> Co-authored-by: Evgeny Danienko <6655321@bk.ru> Co-authored-by: Dmitry <46797839+dkeysil@users.noreply.github.com> * core, miner: add sub-spans for tracing (#753) * core, miner: add sub-spans for tracing * fix linters * core: add logs for debugging * core: add more logs to print tdd while reorg * fix linters * core: minor fix * core: remove debug logs * core: use different span for write block and set head * core: use internal context for sending traces (#755) * core: add : impossible reorg block dump (#754) * add : impossible reorg block dump * chg : 3 seperate files for impossoble reorg dump * add : use exportBlocks method and RLP blocks before writing * chg : small changes * bump : go version from 1.19 to 1.20.1 (#761) * Revert "bump : go version from 1.19 to 1.20.1 (#761)" This reverts commit4561012af9. * core/vm: use optimized bigint (#26021) * Add holiman/big * Fix linter * Bump version to v0.3.5 * fix lints from develop (few lints decided to appear from code that was untouched, weird) * upgrade crypto lib version (#770) * bump dep : github.com/Masterminds/goutils to v1.1.1 (#769) * mardizzone/pos-1313: bump crypto dependency (#772) * dev: chg: bumd net dependency * dev: chg: bump crypto dependency * dev: chg: bump crypto dependency * bump dep : golang.org/x/net to v0.8.0 (#771) * Verify validator set against local contract on receiving an end-of-sprint block (#768) * Verify validator set against local contract on receiving an end-of-sprint block * Fix tests * Respect error returned by ParseValidators * Keep going back until a parent block presents * core/txpool: implement DoS defenses from geth (#778) * Hotfixes and deps bump (#776) * dev: chg: bump deps * internal/cli/server, rpc: lower down http readtimeout to 10s * dev: chg: get p2p adapter * dev: chg: lower down jsonrpc readtimeout to 10s * cherry-pick txpool optimisation changes * add check for empty lists in txpool (#704) * add check * linters * core, miner: add empty instrumentation name for tracing --------- Co-authored-by: Raneet Debnath <raneetdebnath10@gmail.com> Co-authored-by: SHIVAM SHARMA <shivam691999@gmail.com> Co-authored-by: Evgeny Danilenko <6655321@bk.ru> Co-authored-by: Manav Darji <manavdarji.india@gmail.com> * packaging,params: bump to v0.3.6 (#782) * v0.3.6 fix (#787) * Fix get validator set in header verifier * chg : commit tx logs from info to debug (#673) * chg : commit tx logs from info to debug * fix : minor changes * chg : miner : commitTransactions-stats moved from info to debug * lint : fix linters * refactor logging * miner : chg : UnauthorizedSignerError to debug * lint : fix lint * fix : log.Logger interface compatibility --------- Co-authored-by: Evgeny Danienko <6655321@bk.ru> * Remove unnecessary sorting of valset from header in verification * dev: chg: version bump --------- Co-authored-by: SHIVAM SHARMA <shivam691999@gmail.com> Co-authored-by: Evgeny Danienko <6655321@bk.ru> Co-authored-by: marcello33 <marcelloardizzone@hotmail.it> * core: improve locks in txpool (#807) * added a write lock to the txs.filter method and a read lock to the txs.reheap method - both of which are called by Filter during reorg adjustments to txpool * txpool reorg locks * more locks * locks * linters * params, packaging: update version for v0.3.8-beta release * core: add logs in reheap --------- Co-authored-by: Alex <dalexwatts@gmail.com> Co-authored-by: Evgeny Danienko <6655321@bk.ru> * Merge qa to master (#808) * Added checks to RPC requests and introduced new flags to customise the parameters (#657) * added a check to reject rpc requests with batch size > the one set using a newly added flag (rpcbatchlimit) * added a check to reject rpc requests whose result size > the one set using a newly added flag (rpcreturndatalimit) * updated the config files and docs * chg : trieTimeout from 60 to 10 mins (#692) * chg : trieTimeout from 60 to 10 mins * chg : cache.timout to 10m from 1h in configs * internal/cli/server : fix : added triesInMemory in config (#691) * changed version from 0.3.0 to 0.3.4-beta (#693) * fix nil state-sync issue, increase grpc limit (#695) * Increase grpc message size limit in pprof * consensus/bor/bor.go : stateSyncs init fixed [Fix #686] * eth/filters: handle nil state-sync before notify * eth/filters: update check Co-authored-by: Jerry <jerrycgh@gmail.com> Co-authored-by: Daniil <daniil.melnik@chainstack.com> * core, tests/bor: add more tests for state-sync validation (#710) * core: add get state sync function for tests * tests/bor: add validation for state sync events post consensus * Arpit/temp bor sync (#701) * Increase grpc message size limit in pprof * ReadBorReceipts improvements * use internal function * fix tests * fetch geth upstread for ReadBorReceiptRLP * Only query bor receipt when the query index is equal to # tx in block body This change reduces the frequency of calling ReadBorReceipt and ReadBorTransaction, which are CPU and db intensive. * Revert "fetch geth upstread for ReadBorReceiptRLP" This reverts commit 2e838a6b1313d26674f3a8df4b044e35dcbf35a0. * Restore ReadBorReceiptRLP * fix bor receipts * remove unused * fix lints --------- Co-authored-by: Jerry <jerrycgh@gmail.com> Co-authored-by: Manav Darji <manavdarji.india@gmail.com> Co-authored-by: Evgeny Danienko <6655321@bk.ru> * Revert "chg : trieTimeout from 60 to 10 mins (#692)" (#720) This reverts commit241843c7e7. * Arpit/add execution pool 2 (#719) * initial * linters * linters * remove timeout * update pool * change pool size function * check nil * check nil * fix tests * Use execution pool from server in all handlers * simplify things * test fix * add support for cli, config * add to cli and config * merge base branch * debug statements * fix bug * atomic pointer timeout * add apis * update workerpool * fix issues * change params * fix issues * fix ipc issue * remove execution pool from IPC * revert * fix tests * mutex * refactor flag and value names * ordering fix * refactor flag and value names * update default ep size to 40 * fix bor start issues * revert file changes * debug statements * fix bug * update workerpool * atomic pointer timeout * add apis * Merge branch 'add-execution-pool' of github.com:maticnetwork/bor into arpit/add-execution-pool * fix issues * change params * fix issues * fix ipc issue * remove execution pool from IPC * revert * merge base branch * Merge branch 'add-execution-pool' of github.com:maticnetwork/bor into arpit/add-execution-pool * mutex * fix tests * Merge branch 'arpit/add-execution-pool' of github.com:maticnetwork/bor into arpit/add-execution-pool * Change default size of execution pool to 40 * refactor flag and value names * fix merge conflicts * ordering fix * refactor flag and value names * update default ep size to 40 * fix bor start issues * revert file changes * fix linters * fix go.mod * change sec to ms * change default value for ep timeout * fix node api calls * comment setter for ep timeout --------- Co-authored-by: Evgeny Danienko <6655321@bk.ru> Co-authored-by: Jerry <jerrycgh@gmail.com> Co-authored-by: Manav Darji <manavdarji.india@gmail.com> * version change (#721) * Event based pprof (#732) * feature * Save pprof to /tmp --------- Co-authored-by: Jerry <jerrycgh@gmail.com> * Cherry-pick changes from develop (#738) * Check if block is nil to prevent panic (#736) * miner: use env for tracing instead of block object (#728) --------- Co-authored-by: Dmitry <46797839+dkeysil@users.noreply.github.com> * add max code init size check in txpool (#739) * Revert "Event based pprof" and update version (#742) * Revert "Event based pprof (#732)" This reverts commit22fa4033e8. * params: update version to 0.3.4-beta3 * packaging/templates: update bor version * internal/ethapi :: Fix : newRPCTransactionFromBlockIndex * fix: remove assignment for bor receipt --------- Co-authored-by: SHIVAM SHARMA <shivam691999@gmail.com> Co-authored-by: Pratik Patil <pratikspatil024@gmail.com> Co-authored-by: Jerry <jerrycgh@gmail.com> Co-authored-by: Daniil <daniil.melnik@chainstack.com> Co-authored-by: Arpit Temani <temaniarpit27@gmail.com> Co-authored-by: Evgeny Danienko <6655321@bk.ru> Co-authored-by: Dmitry <46797839+dkeysil@users.noreply.github.com> * Setting up bor to use hosted 18.04 runner as ubuntu provided 18.04 runner is end of life --------- Co-authored-by: SHIVAM SHARMA <shivam691999@gmail.com> Co-authored-by: Pratik Patil <pratikspatil024@gmail.com> Co-authored-by: Jerry <jerrycgh@gmail.com> Co-authored-by: Daniil <daniil.melnik@chainstack.com> Co-authored-by: Arpit Temani <temaniarpit27@gmail.com> Co-authored-by: Evgeny Danienko <6655321@bk.ru> Co-authored-by: Dmitry <46797839+dkeysil@users.noreply.github.com> Co-authored-by: Martin Holst Swende <martin@swende.se> Co-authored-by: marcello33 <marcelloardizzone@hotmail.it> Co-authored-by: Raneet Debnath <raneetdebnath10@gmail.com> Co-authored-by: Raneet Debnath <35629432+Raneet10@users.noreply.github.com> Co-authored-by: Alex <dalexwatts@gmail.com> Co-authored-by: Daniel Jones <djones@polygon.technology>
This commit is contained in:
parent
a85370115e
commit
ac353affa3
69 changed files with 4245 additions and 598 deletions
4
.github/workflows/packager.yml
vendored
4
.github/workflows/packager.yml
vendored
|
|
@ -12,7 +12,9 @@ on:
|
|||
|
||||
jobs:
|
||||
build:
|
||||
runs-on: ubuntu-18.04
|
||||
runs-on:
|
||||
group: ubuntu-runners
|
||||
labels: 18.04RunnerT2Large
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v2
|
||||
|
|
|
|||
7
Makefile
7
Makefile
|
|
@ -59,7 +59,10 @@ ios:
|
|||
@echo "Import \"$(GOBIN)/Geth.framework\" to use the library."
|
||||
|
||||
test:
|
||||
$(GOTEST) --timeout 5m -shuffle=on -cover -coverprofile=cover.out $(TESTALL)
|
||||
$(GOTEST) --timeout 5m -shuffle=on -cover -short -coverprofile=cover.out -covermode=atomic $(TESTALL)
|
||||
|
||||
test-txpool-race:
|
||||
$(GOTEST) -run=TestPoolMiningDataRaces --timeout 600m -race -v ./core/
|
||||
|
||||
test-race:
|
||||
$(GOTEST) --timeout 15m -race -shuffle=on $(TESTALL)
|
||||
|
|
@ -75,7 +78,7 @@ lint:
|
|||
|
||||
lintci-deps:
|
||||
rm -f ./build/bin/golangci-lint
|
||||
curl -sSfL https://raw.githubusercontent.com/golangci/golangci-lint/master/install.sh | sh -s -- -b ./build/bin v1.48.0
|
||||
curl -sSfL https://raw.githubusercontent.com/golangci/golangci-lint/master/install.sh | sh -s -- -b ./build/bin v1.50.1
|
||||
|
||||
goimports:
|
||||
goimports -local "$(PACKAGE)" -w .
|
||||
|
|
|
|||
|
|
@ -94,7 +94,7 @@ syncmode = "full"
|
|||
# vhosts = ["*"]
|
||||
# corsdomain = ["*"]
|
||||
# [jsonrpc.timeouts]
|
||||
# read = "30s"
|
||||
# read = "10s"
|
||||
# write = "30s"
|
||||
# idle = "2m0s"
|
||||
|
||||
|
|
|
|||
|
|
@ -24,6 +24,8 @@ import (
|
|||
"os"
|
||||
"strings"
|
||||
|
||||
"gopkg.in/urfave/cli.v1"
|
||||
|
||||
"github.com/ethereum/go-ethereum/common"
|
||||
"github.com/ethereum/go-ethereum/common/hexutil"
|
||||
"github.com/ethereum/go-ethereum/core"
|
||||
|
|
@ -32,7 +34,6 @@ import (
|
|||
"github.com/ethereum/go-ethereum/params"
|
||||
"github.com/ethereum/go-ethereum/rlp"
|
||||
"github.com/ethereum/go-ethereum/tests"
|
||||
"gopkg.in/urfave/cli.v1"
|
||||
)
|
||||
|
||||
type result struct {
|
||||
|
|
|
|||
|
|
@ -1,6 +1,7 @@
|
|||
package debug
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"runtime"
|
||||
)
|
||||
|
||||
|
|
@ -26,3 +27,26 @@ func Callers(show int) []string {
|
|||
|
||||
return callers
|
||||
}
|
||||
|
||||
func CodeLine() (string, string, int) {
|
||||
pc, filename, line, _ := runtime.Caller(1)
|
||||
return runtime.FuncForPC(pc).Name(), filename, line
|
||||
}
|
||||
|
||||
func CodeLineStr() string {
|
||||
pc, filename, line, _ := runtime.Caller(1)
|
||||
return fmt.Sprintf("%s:%d - %s", filename, line, runtime.FuncForPC(pc).Name())
|
||||
}
|
||||
|
||||
func Stack(all bool) []byte {
|
||||
buf := make([]byte, 4096)
|
||||
|
||||
for {
|
||||
n := runtime.Stack(buf, all)
|
||||
if n < len(buf) {
|
||||
return buf[:n]
|
||||
}
|
||||
|
||||
buf = make([]byte, 2*len(buf))
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -20,6 +20,8 @@ package math
|
|||
import (
|
||||
"fmt"
|
||||
"math/big"
|
||||
|
||||
"github.com/holiman/uint256"
|
||||
)
|
||||
|
||||
// Various big integer limit values.
|
||||
|
|
@ -132,6 +134,7 @@ func MustParseBig256(s string) *big.Int {
|
|||
// BigPow returns a ** b as a big integer.
|
||||
func BigPow(a, b int64) *big.Int {
|
||||
r := big.NewInt(a)
|
||||
|
||||
return r.Exp(r, big.NewInt(b), nil)
|
||||
}
|
||||
|
||||
|
|
@ -140,6 +143,15 @@ func BigMax(x, y *big.Int) *big.Int {
|
|||
if x.Cmp(y) < 0 {
|
||||
return y
|
||||
}
|
||||
|
||||
return x
|
||||
}
|
||||
|
||||
func BigMaxUint(x, y *uint256.Int) *uint256.Int {
|
||||
if x.Lt(y) {
|
||||
return y
|
||||
}
|
||||
|
||||
return x
|
||||
}
|
||||
|
||||
|
|
@ -148,6 +160,15 @@ func BigMin(x, y *big.Int) *big.Int {
|
|||
if x.Cmp(y) > 0 {
|
||||
return y
|
||||
}
|
||||
|
||||
return x
|
||||
}
|
||||
|
||||
func BigMinUint256(x, y *uint256.Int) *uint256.Int {
|
||||
if x.Gt(y) {
|
||||
return y
|
||||
}
|
||||
|
||||
return x
|
||||
}
|
||||
|
||||
|
|
|
|||
23
common/math/uint.go
Normal file
23
common/math/uint.go
Normal file
|
|
@ -0,0 +1,23 @@
|
|||
package math
|
||||
|
||||
import (
|
||||
"math/big"
|
||||
|
||||
"github.com/holiman/uint256"
|
||||
)
|
||||
|
||||
var (
|
||||
U0 = uint256.NewInt(0)
|
||||
U1 = uint256.NewInt(1)
|
||||
U100 = uint256.NewInt(100)
|
||||
)
|
||||
|
||||
func U256LTE(a, b *uint256.Int) bool {
|
||||
return a.Lt(b) || a.Eq(b)
|
||||
}
|
||||
|
||||
func FromBig(v *big.Int) *uint256.Int {
|
||||
u, _ := uint256.FromBig(v)
|
||||
|
||||
return u
|
||||
}
|
||||
9
common/time.go
Normal file
9
common/time.go
Normal file
|
|
@ -0,0 +1,9 @@
|
|||
package common
|
||||
|
||||
import "time"
|
||||
|
||||
const TimeMilliseconds = "15:04:05.000"
|
||||
|
||||
func NowMilliseconds() string {
|
||||
return time.Now().Format(TimeMilliseconds)
|
||||
}
|
||||
|
|
@ -4,6 +4,7 @@ import (
|
|||
"context"
|
||||
"time"
|
||||
|
||||
"go.opentelemetry.io/otel"
|
||||
"go.opentelemetry.io/otel/attribute"
|
||||
"go.opentelemetry.io/otel/trace"
|
||||
)
|
||||
|
|
@ -51,11 +52,16 @@ func Trace(ctx context.Context, spanName string) (context.Context, trace.Span) {
|
|||
return tr.Start(ctx, spanName)
|
||||
}
|
||||
|
||||
func Exec(ctx context.Context, spanName string, opts ...Option) {
|
||||
func Exec(ctx context.Context, instrumentationName, spanName string, opts ...Option) {
|
||||
var span trace.Span
|
||||
|
||||
tr := FromContext(ctx)
|
||||
|
||||
if tr == nil && len(instrumentationName) != 0 {
|
||||
tr = otel.GetTracerProvider().Tracer(instrumentationName)
|
||||
ctx = WithTracer(ctx, tr)
|
||||
}
|
||||
|
||||
if tr != nil {
|
||||
ctx, span = tr.Start(ctx, spanName)
|
||||
}
|
||||
|
|
@ -85,7 +91,7 @@ func ElapsedTime(ctx context.Context, span trace.Span, msg string, fn func(conte
|
|||
fn(ctx, span)
|
||||
|
||||
if span != nil {
|
||||
span.SetAttributes(attribute.Int(msg, int(time.Since(now).Milliseconds())))
|
||||
span.SetAttributes(attribute.Int(msg, int(time.Since(now).Microseconds())))
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -298,6 +298,14 @@ func (c *Bor) VerifyHeader(chain consensus.ChainHeaderReader, header *types.Head
|
|||
return c.verifyHeader(chain, header, nil)
|
||||
}
|
||||
|
||||
func (c *Bor) GetSpanner() Spanner {
|
||||
return c.spanner
|
||||
}
|
||||
|
||||
func (c *Bor) SetSpanner(spanner Spanner) {
|
||||
c.spanner = spanner
|
||||
}
|
||||
|
||||
// VerifyHeaders is similar to VerifyHeader, but verifies a batch of headers. The
|
||||
// method returns a quit channel to abort the operations and a results channel to
|
||||
// retrieve the async verifications (the order is that of the input slice).
|
||||
|
|
@ -454,6 +462,33 @@ func (c *Bor) verifyCascadingFields(chain consensus.ChainHeaderReader, header *t
|
|||
return err
|
||||
}
|
||||
|
||||
// Verify the validator list match the local contract
|
||||
if IsSprintStart(number+1, c.config.CalculateSprint(number)) {
|
||||
newValidators, err := c.spanner.GetCurrentValidatorsByBlockNrOrHash(context.Background(), rpc.BlockNumberOrHashWithNumber(rpc.LatestBlockNumber), number+1)
|
||||
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
sort.Sort(valset.ValidatorsByAddress(newValidators))
|
||||
|
||||
headerVals, err := valset.ParseValidators(header.Extra[extraVanity : len(header.Extra)-extraSeal])
|
||||
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if len(newValidators) != len(headerVals) {
|
||||
return errInvalidSpanValidators
|
||||
}
|
||||
|
||||
for i, val := range newValidators {
|
||||
if !bytes.Equal(val.HeaderBytes(), headerVals[i].HeaderBytes()) {
|
||||
return errInvalidSpanValidators
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// verify the validator list in the last sprint block
|
||||
if IsSprintStart(number, c.config.CalculateSprint(number)) {
|
||||
parentValidatorBytes := parent.Extra[extraVanity : len(parent.Extra)-extraSeal]
|
||||
|
|
@ -518,7 +553,7 @@ func (c *Bor) snapshot(chain consensus.ChainHeaderReader, number uint64, hash co
|
|||
hash := checkpoint.Hash()
|
||||
|
||||
// get validators and current span
|
||||
validators, err := c.spanner.GetCurrentValidators(context.Background(), hash, number+1)
|
||||
validators, err := c.spanner.GetCurrentValidatorsByHash(context.Background(), hash, number+1)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
|
@ -688,7 +723,7 @@ func (c *Bor) Prepare(chain consensus.ChainHeaderReader, header *types.Header) e
|
|||
|
||||
// get validator set if number
|
||||
if IsSprintStart(number+1, c.config.CalculateSprint(number)) {
|
||||
newValidators, err := c.spanner.GetCurrentValidators(context.Background(), header.ParentHash, number+1)
|
||||
newValidators, err := c.spanner.GetCurrentValidatorsByHash(context.Background(), header.ParentHash, number+1)
|
||||
if err != nil {
|
||||
return errUnknownValidators
|
||||
}
|
||||
|
|
@ -821,7 +856,7 @@ func (c *Bor) FinalizeAndAssemble(ctx context.Context, chain consensus.ChainHead
|
|||
if IsSprintStart(headerNumber, c.config.CalculateSprint(headerNumber)) {
|
||||
cx := statefull.ChainContext{Chain: chain, Bor: c}
|
||||
|
||||
tracing.Exec(finalizeCtx, "bor.checkAndCommitSpan", func(ctx context.Context, span trace.Span) {
|
||||
tracing.Exec(finalizeCtx, "", "bor.checkAndCommitSpan", func(ctx context.Context, span trace.Span) {
|
||||
// check and commit span
|
||||
err = c.checkAndCommitSpan(finalizeCtx, state, header, cx)
|
||||
})
|
||||
|
|
@ -832,7 +867,7 @@ func (c *Bor) FinalizeAndAssemble(ctx context.Context, chain consensus.ChainHead
|
|||
}
|
||||
|
||||
if c.HeimdallClient != nil {
|
||||
tracing.Exec(finalizeCtx, "bor.checkAndCommitSpan", func(ctx context.Context, span trace.Span) {
|
||||
tracing.Exec(finalizeCtx, "", "bor.checkAndCommitSpan", func(ctx context.Context, span trace.Span) {
|
||||
// commit states
|
||||
stateSyncData, err = c.CommitStates(finalizeCtx, state, header, cx)
|
||||
})
|
||||
|
|
@ -844,7 +879,7 @@ func (c *Bor) FinalizeAndAssemble(ctx context.Context, chain consensus.ChainHead
|
|||
}
|
||||
}
|
||||
|
||||
tracing.Exec(finalizeCtx, "bor.changeContractCodeIfNeeded", func(ctx context.Context, span trace.Span) {
|
||||
tracing.Exec(finalizeCtx, "", "bor.changeContractCodeIfNeeded", func(ctx context.Context, span trace.Span) {
|
||||
err = c.changeContractCodeIfNeeded(headerNumber, state)
|
||||
})
|
||||
|
||||
|
|
@ -854,7 +889,7 @@ func (c *Bor) FinalizeAndAssemble(ctx context.Context, chain consensus.ChainHead
|
|||
}
|
||||
|
||||
// No block rewards in PoA, so the state remains as it is
|
||||
tracing.Exec(finalizeCtx, "bor.IntermediateRoot", func(ctx context.Context, span trace.Span) {
|
||||
tracing.Exec(finalizeCtx, "", "bor.IntermediateRoot", func(ctx context.Context, span trace.Span) {
|
||||
header.Root = state.IntermediateRoot(chain.Config().IsEIP158(header.Number))
|
||||
})
|
||||
|
||||
|
|
@ -1218,7 +1253,7 @@ func (c *Bor) SetHeimdallClient(h IHeimdallClient) {
|
|||
}
|
||||
|
||||
func (c *Bor) GetCurrentValidators(ctx context.Context, headerHash common.Hash, blockNumber uint64) ([]*valset.Validator, error) {
|
||||
return c.spanner.GetCurrentValidators(ctx, headerHash, blockNumber)
|
||||
return c.spanner.GetCurrentValidatorsByHash(ctx, headerHash, blockNumber)
|
||||
}
|
||||
|
||||
//
|
||||
|
|
|
|||
|
|
@ -89,7 +89,7 @@ func (c *ChainSpanner) GetCurrentSpan(ctx context.Context, headerHash common.Has
|
|||
}
|
||||
|
||||
// GetCurrentValidators get current validators
|
||||
func (c *ChainSpanner) GetCurrentValidators(ctx context.Context, headerHash common.Hash, blockNumber uint64) ([]*valset.Validator, error) {
|
||||
func (c *ChainSpanner) GetCurrentValidatorsByBlockNrOrHash(ctx context.Context, blockNrOrHash rpc.BlockNumberOrHash, blockNumber uint64) ([]*valset.Validator, error) {
|
||||
ctx, cancel := context.WithCancel(ctx)
|
||||
defer cancel()
|
||||
|
||||
|
|
@ -107,16 +107,13 @@ func (c *ChainSpanner) GetCurrentValidators(ctx context.Context, headerHash comm
|
|||
toAddress := c.validatorContractAddress
|
||||
gas := (hexutil.Uint64)(uint64(math.MaxUint64 / 2))
|
||||
|
||||
// block
|
||||
blockNr := rpc.BlockNumberOrHashWithHash(headerHash, false)
|
||||
|
||||
result, err := c.ethAPI.Call(ctx, ethapi.TransactionArgs{
|
||||
Gas: &gas,
|
||||
To: &toAddress,
|
||||
Data: &msgData,
|
||||
}, blockNr, nil)
|
||||
}, blockNrOrHash, nil)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
return nil, err
|
||||
}
|
||||
|
||||
var (
|
||||
|
|
@ -144,6 +141,12 @@ func (c *ChainSpanner) GetCurrentValidators(ctx context.Context, headerHash comm
|
|||
return valz, nil
|
||||
}
|
||||
|
||||
func (c *ChainSpanner) GetCurrentValidatorsByHash(ctx context.Context, headerHash common.Hash, blockNumber uint64) ([]*valset.Validator, error) {
|
||||
blockNr := rpc.BlockNumberOrHashWithHash(headerHash, false)
|
||||
|
||||
return c.GetCurrentValidatorsByBlockNrOrHash(ctx, blockNr, blockNumber)
|
||||
}
|
||||
|
||||
const method = "commitSpan"
|
||||
|
||||
func (c *ChainSpanner) CommitSpan(ctx context.Context, heimdallSpan HeimdallSpan, state *state.StateDB, header *types.Header, chainContext core.ChainContext) error {
|
||||
|
|
|
|||
|
|
@ -9,11 +9,13 @@ 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/rpc"
|
||||
)
|
||||
|
||||
//go:generate mockgen -destination=./span_mock.go -package=bor . Spanner
|
||||
type Spanner interface {
|
||||
GetCurrentSpan(ctx context.Context, headerHash common.Hash) (*span.Span, error)
|
||||
GetCurrentValidators(ctx context.Context, headerHash common.Hash, blockNumber uint64) ([]*valset.Validator, error)
|
||||
GetCurrentValidatorsByHash(ctx context.Context, headerHash common.Hash, blockNumber uint64) ([]*valset.Validator, error)
|
||||
GetCurrentValidatorsByBlockNrOrHash(ctx context.Context, blockNrOrHash rpc.BlockNumberOrHash, blockNumber uint64) ([]*valset.Validator, error)
|
||||
CommitSpan(ctx context.Context, heimdallSpan span.HeimdallSpan, state *state.StateDB, header *types.Header, chainContext core.ChainContext) error
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
// Code generated by MockGen. DO NOT EDIT.
|
||||
// Source: github.com/ethereum/go-ethereum/consensus/bor (interfaces: Spanner)
|
||||
// Source: consensus/bor/span.go
|
||||
|
||||
// Package bor is a generated GoMock package.
|
||||
package bor
|
||||
|
|
@ -14,6 +14,7 @@ import (
|
|||
core "github.com/ethereum/go-ethereum/core"
|
||||
state "github.com/ethereum/go-ethereum/core/state"
|
||||
types "github.com/ethereum/go-ethereum/core/types"
|
||||
rpc "github.com/ethereum/go-ethereum/rpc"
|
||||
gomock "github.com/golang/mock/gomock"
|
||||
)
|
||||
|
||||
|
|
@ -41,45 +42,60 @@ func (m *MockSpanner) EXPECT() *MockSpannerMockRecorder {
|
|||
}
|
||||
|
||||
// CommitSpan mocks base method.
|
||||
func (m *MockSpanner) CommitSpan(arg0 context.Context, arg1 span.HeimdallSpan, arg2 *state.StateDB, arg3 *types.Header, arg4 core.ChainContext) error {
|
||||
func (m *MockSpanner) CommitSpan(ctx context.Context, heimdallSpan span.HeimdallSpan, state *state.StateDB, header *types.Header, chainContext core.ChainContext) error {
|
||||
m.ctrl.T.Helper()
|
||||
ret := m.ctrl.Call(m, "CommitSpan", arg0, arg1, arg2, arg3, arg4)
|
||||
ret := m.ctrl.Call(m, "CommitSpan", ctx, heimdallSpan, state, header, chainContext)
|
||||
ret0, _ := ret[0].(error)
|
||||
return ret0
|
||||
}
|
||||
|
||||
// CommitSpan indicates an expected call of CommitSpan.
|
||||
func (mr *MockSpannerMockRecorder) CommitSpan(arg0, arg1, arg2, arg3, arg4 interface{}) *gomock.Call {
|
||||
func (mr *MockSpannerMockRecorder) CommitSpan(ctx, heimdallSpan, state, header, chainContext interface{}) *gomock.Call {
|
||||
mr.mock.ctrl.T.Helper()
|
||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "CommitSpan", reflect.TypeOf((*MockSpanner)(nil).CommitSpan), arg0, arg1, arg2, arg3, arg4)
|
||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "CommitSpan", reflect.TypeOf((*MockSpanner)(nil).CommitSpan), ctx, heimdallSpan, state, header, chainContext)
|
||||
}
|
||||
|
||||
// GetCurrentSpan mocks base method.
|
||||
func (m *MockSpanner) GetCurrentSpan(arg0 context.Context, arg1 common.Hash) (*span.Span, error) {
|
||||
func (m *MockSpanner) GetCurrentSpan(ctx context.Context, headerHash common.Hash) (*span.Span, error) {
|
||||
m.ctrl.T.Helper()
|
||||
ret := m.ctrl.Call(m, "GetCurrentSpan", arg0, arg1)
|
||||
ret := m.ctrl.Call(m, "GetCurrentSpan", ctx, headerHash)
|
||||
ret0, _ := ret[0].(*span.Span)
|
||||
ret1, _ := ret[1].(error)
|
||||
return ret0, ret1
|
||||
}
|
||||
|
||||
// GetCurrentSpan indicates an expected call of GetCurrentSpan.
|
||||
func (mr *MockSpannerMockRecorder) GetCurrentSpan(arg0, arg1 interface{}) *gomock.Call {
|
||||
func (mr *MockSpannerMockRecorder) GetCurrentSpan(ctx, headerHash interface{}) *gomock.Call {
|
||||
mr.mock.ctrl.T.Helper()
|
||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetCurrentSpan", reflect.TypeOf((*MockSpanner)(nil).GetCurrentSpan), arg0, arg1)
|
||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetCurrentSpan", reflect.TypeOf((*MockSpanner)(nil).GetCurrentSpan), ctx, headerHash)
|
||||
}
|
||||
|
||||
// GetCurrentValidators mocks base method.
|
||||
func (m *MockSpanner) GetCurrentValidators(arg0 context.Context, arg1 common.Hash, arg2 uint64) ([]*valset.Validator, error) {
|
||||
// GetCurrentValidatorsByBlockNrOrHash mocks base method.
|
||||
func (m *MockSpanner) GetCurrentValidatorsByBlockNrOrHash(ctx context.Context, blockNrOrHash rpc.BlockNumberOrHash, blockNumber uint64) ([]*valset.Validator, error) {
|
||||
m.ctrl.T.Helper()
|
||||
ret := m.ctrl.Call(m, "GetCurrentValidators", arg0, arg1, arg2)
|
||||
ret := m.ctrl.Call(m, "GetCurrentValidatorsByBlockNrOrHash", ctx, blockNrOrHash, blockNumber)
|
||||
ret0, _ := ret[0].([]*valset.Validator)
|
||||
ret1, _ := ret[1].(error)
|
||||
return ret0, ret1
|
||||
}
|
||||
|
||||
// GetCurrentValidators indicates an expected call of GetCurrentValidators.
|
||||
func (mr *MockSpannerMockRecorder) GetCurrentValidators(arg0, arg1, arg2 interface{}) *gomock.Call {
|
||||
// GetCurrentValidatorsByBlockNrOrHash indicates an expected call of GetCurrentValidatorsByBlockNrOrHash.
|
||||
func (mr *MockSpannerMockRecorder) GetCurrentValidatorsByBlockNrOrHash(ctx, blockNrOrHash, blockNumber interface{}) *gomock.Call {
|
||||
mr.mock.ctrl.T.Helper()
|
||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetCurrentValidators", reflect.TypeOf((*MockSpanner)(nil).GetCurrentValidators), arg0, arg1, arg2)
|
||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetCurrentValidatorsByBlockNrOrHash", reflect.TypeOf((*MockSpanner)(nil).GetCurrentValidatorsByBlockNrOrHash), ctx, blockNrOrHash, blockNumber)
|
||||
}
|
||||
|
||||
// GetCurrentValidatorsByHash mocks base method.
|
||||
func (m *MockSpanner) GetCurrentValidatorsByHash(ctx context.Context, headerHash common.Hash, blockNumber uint64) ([]*valset.Validator, error) {
|
||||
m.ctrl.T.Helper()
|
||||
ret := m.ctrl.Call(m, "GetCurrentValidatorsByHash", ctx, headerHash, blockNumber)
|
||||
ret0, _ := ret[0].([]*valset.Validator)
|
||||
ret1, _ := ret[1].(error)
|
||||
return ret0, ret1
|
||||
}
|
||||
|
||||
// GetCurrentValidatorsByHash indicates an expected call of GetCurrentValidatorsByHash.
|
||||
func (mr *MockSpannerMockRecorder) GetCurrentValidatorsByHash(ctx, headerHash, blockNumber interface{}) *gomock.Call {
|
||||
mr.mock.ctrl.T.Helper()
|
||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetCurrentValidatorsByHash", reflect.TypeOf((*MockSpanner)(nil).GetCurrentValidatorsByHash), ctx, headerHash, blockNumber)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -20,6 +20,8 @@ import (
|
|||
"fmt"
|
||||
"math/big"
|
||||
|
||||
"github.com/holiman/uint256"
|
||||
|
||||
"github.com/ethereum/go-ethereum/common"
|
||||
"github.com/ethereum/go-ethereum/common/math"
|
||||
"github.com/ethereum/go-ethereum/core/types"
|
||||
|
|
@ -92,3 +94,54 @@ func CalcBaseFee(config *params.ChainConfig, parent *types.Header) *big.Int {
|
|||
)
|
||||
}
|
||||
}
|
||||
|
||||
// CalcBaseFee calculates the basefee of the header.
|
||||
func CalcBaseFeeUint(config *params.ChainConfig, parent *types.Header) *uint256.Int {
|
||||
var (
|
||||
initialBaseFeeUint = uint256.NewInt(params.InitialBaseFee)
|
||||
baseFeeChangeDenominatorUint64 = params.BaseFeeChangeDenominator(config.Bor, parent.Number)
|
||||
baseFeeChangeDenominatorUint = uint256.NewInt(baseFeeChangeDenominatorUint64)
|
||||
)
|
||||
|
||||
// If the current block is the first EIP-1559 block, return the InitialBaseFee.
|
||||
if !config.IsLondon(parent.Number) {
|
||||
return initialBaseFeeUint.Clone()
|
||||
}
|
||||
|
||||
var (
|
||||
parentGasTarget = parent.GasLimit / params.ElasticityMultiplier
|
||||
parentGasTargetBig = uint256.NewInt(parentGasTarget)
|
||||
)
|
||||
|
||||
// If the parent gasUsed is the same as the target, the baseFee remains unchanged.
|
||||
if parent.GasUsed == parentGasTarget {
|
||||
return math.FromBig(parent.BaseFee)
|
||||
}
|
||||
|
||||
if parent.GasUsed > parentGasTarget {
|
||||
// If the parent block used more gas than its target, the baseFee should increase.
|
||||
gasUsedDelta := uint256.NewInt(parent.GasUsed - parentGasTarget)
|
||||
|
||||
parentBaseFee := math.FromBig(parent.BaseFee)
|
||||
x := gasUsedDelta.Mul(parentBaseFee, gasUsedDelta)
|
||||
y := x.Div(x, parentGasTargetBig)
|
||||
baseFeeDelta := math.BigMaxUint(
|
||||
x.Div(y, baseFeeChangeDenominatorUint),
|
||||
math.U1,
|
||||
)
|
||||
|
||||
return x.Add(parentBaseFee, baseFeeDelta)
|
||||
}
|
||||
|
||||
// Otherwise if the parent block used less gas than its target, the baseFee should decrease.
|
||||
gasUsedDelta := uint256.NewInt(parentGasTarget - parent.GasUsed)
|
||||
parentBaseFee := math.FromBig(parent.BaseFee)
|
||||
x := gasUsedDelta.Mul(parentBaseFee, gasUsedDelta)
|
||||
y := x.Div(x, parentGasTargetBig)
|
||||
baseFeeDelta := x.Div(y, baseFeeChangeDenominatorUint)
|
||||
|
||||
return math.BigMaxUint(
|
||||
x.Sub(parentBaseFee, baseFeeDelta),
|
||||
math.U0.Clone(),
|
||||
)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -18,21 +18,29 @@
|
|||
package core
|
||||
|
||||
import (
|
||||
"compress/gzip"
|
||||
"context"
|
||||
"errors"
|
||||
"fmt"
|
||||
"io"
|
||||
"math/big"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"sort"
|
||||
"strings"
|
||||
"sync"
|
||||
"sync/atomic"
|
||||
"time"
|
||||
|
||||
lru "github.com/hashicorp/golang-lru"
|
||||
"go.opentelemetry.io/otel/attribute"
|
||||
"go.opentelemetry.io/otel/trace"
|
||||
|
||||
"github.com/ethereum/go-ethereum"
|
||||
"github.com/ethereum/go-ethereum/common"
|
||||
"github.com/ethereum/go-ethereum/common/mclock"
|
||||
"github.com/ethereum/go-ethereum/common/prque"
|
||||
"github.com/ethereum/go-ethereum/common/tracing"
|
||||
"github.com/ethereum/go-ethereum/consensus"
|
||||
"github.com/ethereum/go-ethereum/core/rawdb"
|
||||
"github.com/ethereum/go-ethereum/core/state"
|
||||
|
|
@ -1349,46 +1357,89 @@ func (bc *BlockChain) writeBlockWithState(block *types.Block, receipts []*types.
|
|||
}
|
||||
|
||||
// WriteBlockWithState writes the block and all associated state to the database.
|
||||
func (bc *BlockChain) WriteBlockAndSetHead(block *types.Block, receipts []*types.Receipt, logs []*types.Log, state *state.StateDB, emitHeadEvent bool) (status WriteStatus, err error) {
|
||||
func (bc *BlockChain) WriteBlockAndSetHead(ctx context.Context, block *types.Block, receipts []*types.Receipt, logs []*types.Log, state *state.StateDB, emitHeadEvent bool) (status WriteStatus, err error) {
|
||||
if !bc.chainmu.TryLock() {
|
||||
return NonStatTy, errChainStopped
|
||||
}
|
||||
defer bc.chainmu.Unlock()
|
||||
|
||||
return bc.writeBlockAndSetHead(block, receipts, logs, state, emitHeadEvent)
|
||||
return bc.writeBlockAndSetHead(ctx, block, receipts, logs, state, emitHeadEvent)
|
||||
}
|
||||
|
||||
// writeBlockAndSetHead writes the block and all associated state to the database,
|
||||
// and also it applies the given block as the new chain head. This function expects
|
||||
// the chain mutex to be held.
|
||||
func (bc *BlockChain) writeBlockAndSetHead(block *types.Block, receipts []*types.Receipt, logs []*types.Log, state *state.StateDB, emitHeadEvent bool) (status WriteStatus, err error) {
|
||||
func (bc *BlockChain) writeBlockAndSetHead(ctx context.Context, block *types.Block, receipts []*types.Receipt, logs []*types.Log, state *state.StateDB, emitHeadEvent bool) (status WriteStatus, err error) {
|
||||
writeBlockAndSetHeadCtx, span := tracing.StartSpan(ctx, "blockchain.writeBlockAndSetHead")
|
||||
defer tracing.EndSpan(span)
|
||||
|
||||
var stateSyncLogs []*types.Log
|
||||
|
||||
if stateSyncLogs, err = bc.writeBlockWithState(block, receipts, logs, state); err != nil {
|
||||
return NonStatTy, err
|
||||
}
|
||||
currentBlock := bc.CurrentBlock()
|
||||
reorg, err := bc.forker.ReorgNeeded(currentBlock.Header(), block.Header())
|
||||
tracing.Exec(writeBlockAndSetHeadCtx, "", "blockchain.writeBlockWithState", func(_ context.Context, span trace.Span) {
|
||||
stateSyncLogs, err = bc.writeBlockWithState(block, receipts, logs, state)
|
||||
tracing.SetAttributes(
|
||||
span,
|
||||
attribute.Int("number", int(block.Number().Uint64())),
|
||||
attribute.Bool("error", err != nil),
|
||||
)
|
||||
})
|
||||
|
||||
if err != nil {
|
||||
return NonStatTy, err
|
||||
}
|
||||
|
||||
currentBlock := bc.CurrentBlock()
|
||||
|
||||
var reorg bool
|
||||
|
||||
tracing.Exec(writeBlockAndSetHeadCtx, "", "blockchain.ReorgNeeded", func(_ context.Context, span trace.Span) {
|
||||
reorg, err = bc.forker.ReorgNeeded(currentBlock.Header(), block.Header())
|
||||
tracing.SetAttributes(
|
||||
span,
|
||||
attribute.Int("number", int(block.Number().Uint64())),
|
||||
attribute.Int("current block", int(currentBlock.Number().Uint64())),
|
||||
attribute.Bool("reorg needed", reorg),
|
||||
attribute.Bool("error", err != nil),
|
||||
)
|
||||
})
|
||||
if err != nil {
|
||||
return NonStatTy, err
|
||||
}
|
||||
|
||||
tracing.Exec(writeBlockAndSetHeadCtx, "", "blockchain.reorg", func(_ context.Context, span trace.Span) {
|
||||
if reorg {
|
||||
// Reorganise the chain if the parent is not the head block
|
||||
if block.ParentHash() != currentBlock.Hash() {
|
||||
if err := bc.reorg(currentBlock, block); err != nil {
|
||||
return NonStatTy, err
|
||||
if err = bc.reorg(currentBlock, block); err != nil {
|
||||
status = NonStatTy
|
||||
}
|
||||
}
|
||||
|
||||
status = CanonStatTy
|
||||
} else {
|
||||
status = SideStatTy
|
||||
}
|
||||
|
||||
tracing.SetAttributes(
|
||||
span,
|
||||
attribute.Int("number", int(block.Number().Uint64())),
|
||||
attribute.Int("current block", int(currentBlock.Number().Uint64())),
|
||||
attribute.Bool("reorg needed", reorg),
|
||||
attribute.Bool("error", err != nil),
|
||||
attribute.String("status", string(status)),
|
||||
)
|
||||
})
|
||||
|
||||
if status == NonStatTy {
|
||||
return
|
||||
}
|
||||
|
||||
// Set new head.
|
||||
if status == CanonStatTy {
|
||||
tracing.Exec(writeBlockAndSetHeadCtx, "", "blockchain.writeHeadBlock", func(_ context.Context, _ trace.Span) {
|
||||
bc.writeHeadBlock(block)
|
||||
})
|
||||
}
|
||||
|
||||
bc.futureBlocks.Remove(block.Hash())
|
||||
|
||||
if status == CanonStatTy {
|
||||
|
|
@ -1785,7 +1836,7 @@ func (bc *BlockChain) insertChain(chain types.Blocks, verifySeals, setHead bool)
|
|||
// Don't set the head, only insert the block
|
||||
_, err = bc.writeBlockWithState(block, receipts, logs, statedb)
|
||||
} else {
|
||||
status, err = bc.writeBlockAndSetHead(block, receipts, logs, statedb, false)
|
||||
status, err = bc.writeBlockAndSetHead(context.Background(), block, receipts, logs, statedb, false)
|
||||
}
|
||||
atomic.StoreUint32(&followupInterrupt, 1)
|
||||
if err != nil {
|
||||
|
|
@ -2194,6 +2245,35 @@ func (bc *BlockChain) reorg(oldBlock, newBlock *types.Block) error {
|
|||
} else {
|
||||
// len(newChain) == 0 && len(oldChain) > 0
|
||||
// rewind the canonical chain to a lower point.
|
||||
|
||||
home, err := os.UserHomeDir()
|
||||
if err != nil {
|
||||
fmt.Println("Impossible reorg : Unable to get user home dir", "Error", err)
|
||||
}
|
||||
outPath := filepath.Join(home, "impossible-reorgs", fmt.Sprintf("%v-impossibleReorg", time.Now().Format(time.RFC3339)))
|
||||
|
||||
if _, err := os.Stat(outPath); errors.Is(err, os.ErrNotExist) {
|
||||
err := os.MkdirAll(outPath, os.ModePerm)
|
||||
if err != nil {
|
||||
log.Error("Impossible reorg : Unable to create Dir", "Error", err)
|
||||
}
|
||||
} else {
|
||||
err = ExportBlocks(oldChain, filepath.Join(outPath, "oldChain.gz"))
|
||||
if err != nil {
|
||||
log.Error("Impossible reorg : Unable to export oldChain", "Error", err)
|
||||
}
|
||||
|
||||
err = ExportBlocks([]*types.Block{oldBlock}, filepath.Join(outPath, "oldBlock.gz"))
|
||||
if err != nil {
|
||||
log.Error("Impossible reorg : Unable to export oldBlock", "Error", err)
|
||||
}
|
||||
|
||||
err = ExportBlocks([]*types.Block{newBlock}, filepath.Join(outPath, "newBlock.gz"))
|
||||
if err != nil {
|
||||
log.Error("Impossible reorg : Unable to export newBlock", "Error", err)
|
||||
}
|
||||
}
|
||||
|
||||
log.Error("Impossible reorg, please file an issue", "oldnum", oldBlock.Number(), "oldhash", oldBlock.Hash(), "oldblocks", len(oldChain), "newnum", newBlock.Number(), "newhash", newBlock.Hash(), "newblocks", len(newChain))
|
||||
}
|
||||
// Insert the new chain(except the head block(reverse order)),
|
||||
|
|
@ -2246,6 +2326,44 @@ func (bc *BlockChain) reorg(oldBlock, newBlock *types.Block) error {
|
|||
return nil
|
||||
}
|
||||
|
||||
// ExportBlocks exports blocks into the specified file, truncating any data
|
||||
// already present in the file.
|
||||
func ExportBlocks(blocks []*types.Block, fn string) error {
|
||||
log.Info("Exporting blockchain", "file", fn)
|
||||
|
||||
// Open the file handle and potentially wrap with a gzip stream
|
||||
fh, err := os.OpenFile(fn, os.O_CREATE|os.O_WRONLY|os.O_TRUNC, os.ModePerm)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer fh.Close()
|
||||
|
||||
var writer io.Writer = fh
|
||||
if strings.HasSuffix(fn, ".gz") {
|
||||
writer = gzip.NewWriter(writer)
|
||||
defer writer.(*gzip.Writer).Close()
|
||||
}
|
||||
// Iterate over the blocks and export them
|
||||
if err := ExportN(writer, blocks); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
log.Info("Exported blocks", "file", fn)
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// ExportBlock writes a block to the given writer.
|
||||
func ExportN(w io.Writer, blocks []*types.Block) error {
|
||||
for _, block := range blocks {
|
||||
if err := block.EncodeRLP(w); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// InsertBlockWithoutSetHead executes the block, runs the necessary verification
|
||||
// upon it and then persist the block and the associate state into the database.
|
||||
// The key difference between the InsertChain is it won't do the canonical chain
|
||||
|
|
|
|||
|
|
@ -1796,7 +1796,7 @@ func testRepair(t *testing.T, tt *rewindTest, snapshots bool) {
|
|||
ethAPIMock.EXPECT().Call(gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any()).AnyTimes()
|
||||
|
||||
spanner := bor.NewMockSpanner(ctrl)
|
||||
spanner.EXPECT().GetCurrentValidators(gomock.Any(), gomock.Any(), gomock.Any()).Return([]*valset.Validator{
|
||||
spanner.EXPECT().GetCurrentValidatorsByHash(gomock.Any(), gomock.Any(), gomock.Any()).Return([]*valset.Validator{
|
||||
{
|
||||
ID: 0,
|
||||
Address: miner.TestBankAddress,
|
||||
|
|
|
|||
|
|
@ -61,11 +61,13 @@ func (journal *txJournal) load(add func([]*types.Transaction) []error) error {
|
|||
if _, err := os.Stat(journal.path); os.IsNotExist(err) {
|
||||
return nil
|
||||
}
|
||||
|
||||
// Open the journal for loading any past transactions
|
||||
input, err := os.Open(journal.path)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
defer input.Close()
|
||||
|
||||
// Temporarily discard any journal additions (don't double add on load)
|
||||
|
|
@ -80,29 +82,35 @@ func (journal *txJournal) load(add func([]*types.Transaction) []error) error {
|
|||
// appropriate progress counters. Then use this method to load all the
|
||||
// journaled transactions in small-ish batches.
|
||||
loadBatch := func(txs types.Transactions) {
|
||||
errs := add(txs)
|
||||
|
||||
dropped = len(errs)
|
||||
|
||||
for _, err := range add(txs) {
|
||||
if err != nil {
|
||||
log.Debug("Failed to add journaled transaction", "err", err)
|
||||
dropped++
|
||||
}
|
||||
}
|
||||
}
|
||||
var (
|
||||
failure error
|
||||
batch types.Transactions
|
||||
)
|
||||
|
||||
for {
|
||||
// Parse the next transaction and terminate on error
|
||||
tx := new(types.Transaction)
|
||||
|
||||
if err = stream.Decode(tx); err != nil {
|
||||
if err != io.EOF {
|
||||
failure = err
|
||||
}
|
||||
|
||||
if batch.Len() > 0 {
|
||||
loadBatch(batch)
|
||||
}
|
||||
|
||||
break
|
||||
}
|
||||
|
||||
// New transaction parsed, queue up for later, import if threshold is reached
|
||||
total++
|
||||
|
||||
|
|
@ -111,6 +119,7 @@ func (journal *txJournal) load(add func([]*types.Transaction) []error) error {
|
|||
batch = batch[:0]
|
||||
}
|
||||
}
|
||||
|
||||
log.Info("Loaded local transaction journal", "transactions", total, "dropped", dropped)
|
||||
|
||||
return failure
|
||||
|
|
|
|||
304
core/tx_list.go
304
core/tx_list.go
|
|
@ -25,8 +25,12 @@ import (
|
|||
"sync/atomic"
|
||||
"time"
|
||||
|
||||
"github.com/holiman/uint256"
|
||||
|
||||
"github.com/ethereum/go-ethereum/common"
|
||||
cmath "github.com/ethereum/go-ethereum/common/math"
|
||||
"github.com/ethereum/go-ethereum/core/types"
|
||||
"github.com/ethereum/go-ethereum/log"
|
||||
)
|
||||
|
||||
// nonceHeap is a heap.Interface implementation over 64bit unsigned integers for
|
||||
|
|
@ -54,7 +58,11 @@ func (h *nonceHeap) Pop() interface{} {
|
|||
type txSortedMap struct {
|
||||
items map[uint64]*types.Transaction // Hash map storing the transaction data
|
||||
index *nonceHeap // Heap of nonces of all the stored transactions (non-strict mode)
|
||||
m sync.RWMutex
|
||||
|
||||
cache types.Transactions // Cache of the transactions already sorted
|
||||
isEmpty bool
|
||||
cacheMu sync.RWMutex
|
||||
}
|
||||
|
||||
// newTxSortedMap creates a new nonce-sorted transaction map.
|
||||
|
|
@ -62,28 +70,55 @@ func newTxSortedMap() *txSortedMap {
|
|||
return &txSortedMap{
|
||||
items: make(map[uint64]*types.Transaction),
|
||||
index: new(nonceHeap),
|
||||
isEmpty: true,
|
||||
}
|
||||
}
|
||||
|
||||
// Get retrieves the current transactions associated with the given nonce.
|
||||
func (m *txSortedMap) Get(nonce uint64) *types.Transaction {
|
||||
m.m.RLock()
|
||||
defer m.m.RUnlock()
|
||||
|
||||
return m.items[nonce]
|
||||
}
|
||||
|
||||
func (m *txSortedMap) Has(nonce uint64) bool {
|
||||
if m == nil {
|
||||
return false
|
||||
}
|
||||
|
||||
m.m.RLock()
|
||||
defer m.m.RUnlock()
|
||||
|
||||
return m.items[nonce] != nil
|
||||
}
|
||||
|
||||
// Put inserts a new transaction into the map, also updating the map's nonce
|
||||
// index. If a transaction already exists with the same nonce, it's overwritten.
|
||||
func (m *txSortedMap) Put(tx *types.Transaction) {
|
||||
m.m.Lock()
|
||||
defer m.m.Unlock()
|
||||
|
||||
nonce := tx.Nonce()
|
||||
if m.items[nonce] == nil {
|
||||
heap.Push(m.index, nonce)
|
||||
}
|
||||
m.items[nonce], m.cache = tx, nil
|
||||
|
||||
m.items[nonce] = tx
|
||||
|
||||
m.cacheMu.Lock()
|
||||
m.isEmpty = true
|
||||
m.cache = nil
|
||||
m.cacheMu.Unlock()
|
||||
}
|
||||
|
||||
// Forward removes all transactions from the map with a nonce lower than the
|
||||
// provided threshold. Every removed transaction is returned for any post-removal
|
||||
// maintenance.
|
||||
func (m *txSortedMap) Forward(threshold uint64) types.Transactions {
|
||||
m.m.Lock()
|
||||
defer m.m.Unlock()
|
||||
|
||||
var removed types.Transactions
|
||||
|
||||
// Pop off heap items until the threshold is reached
|
||||
|
|
@ -92,10 +127,15 @@ func (m *txSortedMap) Forward(threshold uint64) types.Transactions {
|
|||
removed = append(removed, m.items[nonce])
|
||||
delete(m.items, nonce)
|
||||
}
|
||||
|
||||
// If we had a cached order, shift the front
|
||||
m.cacheMu.Lock()
|
||||
if m.cache != nil {
|
||||
hitCacheCounter.Inc(1)
|
||||
m.cache = m.cache[len(removed):]
|
||||
}
|
||||
m.cacheMu.Unlock()
|
||||
|
||||
return removed
|
||||
}
|
||||
|
||||
|
|
@ -105,21 +145,51 @@ func (m *txSortedMap) Forward(threshold uint64) types.Transactions {
|
|||
// If you want to do several consecutive filterings, it's therefore better to first
|
||||
// do a .filter(func1) followed by .Filter(func2) or reheap()
|
||||
func (m *txSortedMap) Filter(filter func(*types.Transaction) bool) types.Transactions {
|
||||
m.m.Lock()
|
||||
defer m.m.Unlock()
|
||||
|
||||
removed := m.filter(filter)
|
||||
// If transactions were removed, the heap and cache are ruined
|
||||
if len(removed) > 0 {
|
||||
m.reheap()
|
||||
m.reheap(false)
|
||||
}
|
||||
return removed
|
||||
}
|
||||
|
||||
func (m *txSortedMap) reheap() {
|
||||
*m.index = make([]uint64, 0, len(m.items))
|
||||
for nonce := range m.items {
|
||||
*m.index = append(*m.index, nonce)
|
||||
func (m *txSortedMap) reheap(withRlock bool) {
|
||||
index := make(nonceHeap, 0, len(m.items))
|
||||
|
||||
if withRlock {
|
||||
m.m.RLock()
|
||||
log.Info("[DEBUG] Acquired lock over txpool map while performing reheap")
|
||||
}
|
||||
heap.Init(m.index)
|
||||
|
||||
for nonce := range m.items {
|
||||
index = append(index, nonce)
|
||||
}
|
||||
|
||||
if withRlock {
|
||||
m.m.RUnlock()
|
||||
}
|
||||
|
||||
heap.Init(&index)
|
||||
|
||||
if withRlock {
|
||||
m.m.Lock()
|
||||
}
|
||||
|
||||
m.index = &index
|
||||
|
||||
if withRlock {
|
||||
m.m.Unlock()
|
||||
}
|
||||
|
||||
m.cacheMu.Lock()
|
||||
m.cache = nil
|
||||
m.isEmpty = true
|
||||
m.cacheMu.Unlock()
|
||||
|
||||
resetCacheGauge.Inc(1)
|
||||
}
|
||||
|
||||
// filter is identical to Filter, but **does not** regenerate the heap. This method
|
||||
|
|
@ -135,7 +205,12 @@ func (m *txSortedMap) filter(filter func(*types.Transaction) bool) types.Transac
|
|||
}
|
||||
}
|
||||
if len(removed) > 0 {
|
||||
m.cacheMu.Lock()
|
||||
m.cache = nil
|
||||
m.isEmpty = true
|
||||
m.cacheMu.Unlock()
|
||||
|
||||
resetCacheGauge.Inc(1)
|
||||
}
|
||||
return removed
|
||||
}
|
||||
|
|
@ -143,45 +218,66 @@ func (m *txSortedMap) filter(filter func(*types.Transaction) bool) types.Transac
|
|||
// Cap places a hard limit on the number of items, returning all transactions
|
||||
// exceeding that limit.
|
||||
func (m *txSortedMap) Cap(threshold int) types.Transactions {
|
||||
m.m.Lock()
|
||||
defer m.m.Unlock()
|
||||
|
||||
// Short circuit if the number of items is under the limit
|
||||
if len(m.items) <= threshold {
|
||||
return nil
|
||||
}
|
||||
|
||||
// Otherwise gather and drop the highest nonce'd transactions
|
||||
var drops types.Transactions
|
||||
|
||||
sort.Sort(*m.index)
|
||||
|
||||
for size := len(m.items); size > threshold; size-- {
|
||||
drops = append(drops, m.items[(*m.index)[size-1]])
|
||||
delete(m.items, (*m.index)[size-1])
|
||||
}
|
||||
|
||||
*m.index = (*m.index)[:threshold]
|
||||
heap.Init(m.index)
|
||||
|
||||
// If we had a cache, shift the back
|
||||
m.cacheMu.Lock()
|
||||
if m.cache != nil {
|
||||
m.cache = m.cache[:len(m.cache)-len(drops)]
|
||||
}
|
||||
m.cacheMu.Unlock()
|
||||
|
||||
return drops
|
||||
}
|
||||
|
||||
// Remove deletes a transaction from the maintained map, returning whether the
|
||||
// transaction was found.
|
||||
func (m *txSortedMap) Remove(nonce uint64) bool {
|
||||
m.m.Lock()
|
||||
defer m.m.Unlock()
|
||||
|
||||
// Short circuit if no transaction is present
|
||||
_, ok := m.items[nonce]
|
||||
if !ok {
|
||||
return false
|
||||
}
|
||||
|
||||
// Otherwise delete the transaction and fix the heap index
|
||||
for i := 0; i < m.index.Len(); i++ {
|
||||
if (*m.index)[i] == nonce {
|
||||
heap.Remove(m.index, i)
|
||||
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
delete(m.items, nonce)
|
||||
|
||||
m.cacheMu.Lock()
|
||||
m.cache = nil
|
||||
m.isEmpty = true
|
||||
m.cacheMu.Unlock()
|
||||
|
||||
resetCacheGauge.Inc(1)
|
||||
|
||||
return true
|
||||
}
|
||||
|
|
@ -194,55 +290,129 @@ func (m *txSortedMap) Remove(nonce uint64) bool {
|
|||
// prevent getting into and invalid state. This is not something that should ever
|
||||
// happen but better to be self correcting than failing!
|
||||
func (m *txSortedMap) Ready(start uint64) types.Transactions {
|
||||
m.m.Lock()
|
||||
defer m.m.Unlock()
|
||||
|
||||
// Short circuit if no transactions are available
|
||||
if m.index.Len() == 0 || (*m.index)[0] > start {
|
||||
return nil
|
||||
}
|
||||
|
||||
// Otherwise start accumulating incremental transactions
|
||||
var ready types.Transactions
|
||||
|
||||
for next := (*m.index)[0]; m.index.Len() > 0 && (*m.index)[0] == next; next++ {
|
||||
ready = append(ready, m.items[next])
|
||||
delete(m.items, next)
|
||||
heap.Pop(m.index)
|
||||
}
|
||||
|
||||
m.cacheMu.Lock()
|
||||
m.cache = nil
|
||||
m.isEmpty = true
|
||||
m.cacheMu.Unlock()
|
||||
|
||||
resetCacheGauge.Inc(1)
|
||||
|
||||
return ready
|
||||
}
|
||||
|
||||
// Len returns the length of the transaction map.
|
||||
func (m *txSortedMap) Len() int {
|
||||
m.m.RLock()
|
||||
defer m.m.RUnlock()
|
||||
|
||||
return len(m.items)
|
||||
}
|
||||
|
||||
func (m *txSortedMap) flatten() types.Transactions {
|
||||
// If the sorting was not cached yet, create and cache it
|
||||
if m.cache == nil {
|
||||
m.cache = make(types.Transactions, 0, len(m.items))
|
||||
m.cacheMu.Lock()
|
||||
defer m.cacheMu.Unlock()
|
||||
|
||||
if m.isEmpty {
|
||||
m.isEmpty = false // to simulate sync.Once
|
||||
|
||||
m.cacheMu.Unlock()
|
||||
|
||||
m.m.RLock()
|
||||
|
||||
cache := make(types.Transactions, 0, len(m.items))
|
||||
|
||||
for _, tx := range m.items {
|
||||
m.cache = append(m.cache, tx)
|
||||
cache = append(cache, tx)
|
||||
}
|
||||
sort.Sort(types.TxByNonce(m.cache))
|
||||
|
||||
m.m.RUnlock()
|
||||
|
||||
// exclude sorting from locks
|
||||
sort.Sort(types.TxByNonce(cache))
|
||||
|
||||
m.cacheMu.Lock()
|
||||
m.cache = cache
|
||||
|
||||
reinitCacheGauge.Inc(1)
|
||||
missCacheCounter.Inc(1)
|
||||
} else {
|
||||
hitCacheCounter.Inc(1)
|
||||
}
|
||||
|
||||
return m.cache
|
||||
}
|
||||
|
||||
func (m *txSortedMap) lastElement() *types.Transaction {
|
||||
// If the sorting was not cached yet, create and cache it
|
||||
m.cacheMu.Lock()
|
||||
defer m.cacheMu.Unlock()
|
||||
|
||||
cache := m.cache
|
||||
|
||||
if m.isEmpty {
|
||||
m.isEmpty = false // to simulate sync.Once
|
||||
|
||||
m.cacheMu.Unlock()
|
||||
|
||||
m.m.RLock()
|
||||
cache = make(types.Transactions, 0, len(m.items))
|
||||
|
||||
for _, tx := range m.items {
|
||||
cache = append(cache, tx)
|
||||
}
|
||||
|
||||
m.m.RUnlock()
|
||||
|
||||
// exclude sorting from locks
|
||||
sort.Sort(types.TxByNonce(cache))
|
||||
|
||||
m.cacheMu.Lock()
|
||||
m.cache = cache
|
||||
|
||||
reinitCacheGauge.Inc(1)
|
||||
missCacheCounter.Inc(1)
|
||||
} else {
|
||||
hitCacheCounter.Inc(1)
|
||||
}
|
||||
|
||||
ln := len(cache)
|
||||
if ln == 0 {
|
||||
return nil
|
||||
}
|
||||
|
||||
return cache[len(cache)-1]
|
||||
}
|
||||
|
||||
// Flatten creates a nonce-sorted slice of transactions based on the loosely
|
||||
// sorted internal representation. The result of the sorting is cached in case
|
||||
// it's requested again before any modifications are made to the contents.
|
||||
func (m *txSortedMap) Flatten() types.Transactions {
|
||||
// Copy the cache to prevent accidental modifications
|
||||
cache := m.flatten()
|
||||
txs := make(types.Transactions, len(cache))
|
||||
copy(txs, cache)
|
||||
return txs
|
||||
return m.flatten()
|
||||
}
|
||||
|
||||
// LastElement returns the last element of a flattened list, thus, the
|
||||
// transaction with the highest nonce
|
||||
func (m *txSortedMap) LastElement() *types.Transaction {
|
||||
cache := m.flatten()
|
||||
return cache[len(cache)-1]
|
||||
return m.lastElement()
|
||||
}
|
||||
|
||||
// txList is a "list" of transactions belonging to an account, sorted by account
|
||||
|
|
@ -253,8 +423,9 @@ type txList struct {
|
|||
strict bool // Whether nonces are strictly continuous or not
|
||||
txs *txSortedMap // Heap indexed sorted hash map of the transactions
|
||||
|
||||
costcap *big.Int // Price of the highest costing transaction (reset only if exceeds balance)
|
||||
costcap *uint256.Int // Price of the highest costing transaction (reset only if exceeds balance)
|
||||
gascap uint64 // Gas limit of the highest spending transaction (reset only if exceeds block limit)
|
||||
totalcost *big.Int // Total cost of all transactions in the list
|
||||
}
|
||||
|
||||
// newTxList create a new transaction list for maintaining nonce-indexable fast,
|
||||
|
|
@ -263,7 +434,7 @@ func newTxList(strict bool) *txList {
|
|||
return &txList{
|
||||
strict: strict,
|
||||
txs: newTxSortedMap(),
|
||||
costcap: new(big.Int),
|
||||
totalcost: new(big.Int),
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -285,31 +456,41 @@ func (l *txList) Add(tx *types.Transaction, priceBump uint64) (bool, *types.Tran
|
|||
if old.GasFeeCapCmp(tx) >= 0 || old.GasTipCapCmp(tx) >= 0 {
|
||||
return false, nil
|
||||
}
|
||||
|
||||
// thresholdFeeCap = oldFC * (100 + priceBump) / 100
|
||||
a := big.NewInt(100 + int64(priceBump))
|
||||
aFeeCap := new(big.Int).Mul(a, old.GasFeeCap())
|
||||
aTip := a.Mul(a, old.GasTipCap())
|
||||
a := uint256.NewInt(100 + priceBump)
|
||||
aFeeCap := uint256.NewInt(0).Mul(a, old.GasFeeCapUint())
|
||||
aTip := a.Mul(a, old.GasTipCapUint())
|
||||
|
||||
// thresholdTip = oldTip * (100 + priceBump) / 100
|
||||
b := big.NewInt(100)
|
||||
b := cmath.U100
|
||||
thresholdFeeCap := aFeeCap.Div(aFeeCap, b)
|
||||
thresholdTip := aTip.Div(aTip, b)
|
||||
|
||||
// We have to ensure that both the new fee cap and tip are higher than the
|
||||
// old ones as well as checking the percentage threshold to ensure that
|
||||
// this is accurate for low (Wei-level) gas price replacements.
|
||||
if tx.GasFeeCapIntCmp(thresholdFeeCap) < 0 || tx.GasTipCapIntCmp(thresholdTip) < 0 {
|
||||
if tx.GasFeeCapUIntLt(thresholdFeeCap) || tx.GasTipCapUIntLt(thresholdTip) {
|
||||
return false, nil
|
||||
}
|
||||
// Old is being replaced, subtract old cost
|
||||
l.subTotalCost([]*types.Transaction{old})
|
||||
}
|
||||
|
||||
// Add new tx cost to totalcost
|
||||
l.totalcost.Add(l.totalcost, tx.Cost())
|
||||
|
||||
// Otherwise overwrite the old transaction with the current one
|
||||
l.txs.Put(tx)
|
||||
if cost := tx.Cost(); l.costcap.Cmp(cost) < 0 {
|
||||
|
||||
if cost := tx.CostUint(); l.costcap == nil || l.costcap.Lt(cost) {
|
||||
l.costcap = cost
|
||||
}
|
||||
|
||||
if gas := tx.Gas(); l.gascap < gas {
|
||||
l.gascap = gas
|
||||
}
|
||||
|
||||
return true, old
|
||||
}
|
||||
|
||||
|
|
@ -317,7 +498,10 @@ func (l *txList) Add(tx *types.Transaction, priceBump uint64) (bool, *types.Tran
|
|||
// provided threshold. Every removed transaction is returned for any post-removal
|
||||
// maintenance.
|
||||
func (l *txList) Forward(threshold uint64) types.Transactions {
|
||||
return l.txs.Forward(threshold)
|
||||
txs := l.txs.Forward(threshold)
|
||||
l.subTotalCost(txs)
|
||||
|
||||
return txs
|
||||
}
|
||||
|
||||
// Filter removes all transactions from the list with a cost or gas limit higher
|
||||
|
|
@ -329,17 +513,20 @@ func (l *txList) Forward(threshold uint64) types.Transactions {
|
|||
// a point in calculating all the costs or if the balance covers all. If the threshold
|
||||
// is lower than the costgas cap, the caps will be reset to a new high after removing
|
||||
// the newly invalidated transactions.
|
||||
func (l *txList) Filter(costLimit *big.Int, gasLimit uint64) (types.Transactions, types.Transactions) {
|
||||
func (l *txList) Filter(costLimit *uint256.Int, gasLimit uint64) (types.Transactions, types.Transactions) {
|
||||
// If all transactions are below the threshold, short circuit
|
||||
if l.costcap.Cmp(costLimit) <= 0 && l.gascap <= gasLimit {
|
||||
if cmath.U256LTE(l.costcap, costLimit) && l.gascap <= gasLimit {
|
||||
return nil, nil
|
||||
}
|
||||
l.costcap = new(big.Int).Set(costLimit) // Lower the caps to the thresholds
|
||||
|
||||
l.costcap = costLimit.Clone() // Lower the caps to the thresholds
|
||||
l.gascap = gasLimit
|
||||
|
||||
// Filter out all the transactions above the account's funds
|
||||
cost := uint256.NewInt(0)
|
||||
removed := l.txs.Filter(func(tx *types.Transaction) bool {
|
||||
return tx.Gas() > gasLimit || tx.Cost().Cmp(costLimit) > 0
|
||||
cost.SetFromBig(tx.Cost())
|
||||
return tx.Gas() > gasLimit || cost.Gt(costLimit)
|
||||
})
|
||||
|
||||
if len(removed) == 0 {
|
||||
|
|
@ -354,16 +541,27 @@ func (l *txList) Filter(costLimit *big.Int, gasLimit uint64) (types.Transactions
|
|||
lowest = nonce
|
||||
}
|
||||
}
|
||||
|
||||
l.txs.m.Lock()
|
||||
invalids = l.txs.filter(func(tx *types.Transaction) bool { return tx.Nonce() > lowest })
|
||||
l.txs.m.Unlock()
|
||||
}
|
||||
l.txs.reheap()
|
||||
// Reset total cost
|
||||
l.subTotalCost(removed)
|
||||
l.subTotalCost(invalids)
|
||||
|
||||
l.txs.reheap(true)
|
||||
|
||||
return removed, invalids
|
||||
}
|
||||
|
||||
// Cap places a hard limit on the number of items, returning all transactions
|
||||
// exceeding that limit.
|
||||
func (l *txList) Cap(threshold int) types.Transactions {
|
||||
return l.txs.Cap(threshold)
|
||||
txs := l.txs.Cap(threshold)
|
||||
l.subTotalCost(txs)
|
||||
|
||||
return txs
|
||||
}
|
||||
|
||||
// Remove deletes a transaction from the maintained list, returning whether the
|
||||
|
|
@ -375,9 +573,14 @@ func (l *txList) Remove(tx *types.Transaction) (bool, types.Transactions) {
|
|||
if removed := l.txs.Remove(nonce); !removed {
|
||||
return false, nil
|
||||
}
|
||||
|
||||
l.subTotalCost([]*types.Transaction{tx})
|
||||
// In strict mode, filter out non-executable transactions
|
||||
if l.strict {
|
||||
return true, l.txs.Filter(func(tx *types.Transaction) bool { return tx.Nonce() > nonce })
|
||||
txs := l.txs.Filter(func(tx *types.Transaction) bool { return tx.Nonce() > nonce })
|
||||
l.subTotalCost(txs)
|
||||
|
||||
return true, txs
|
||||
}
|
||||
return true, nil
|
||||
}
|
||||
|
|
@ -390,7 +593,10 @@ func (l *txList) Remove(tx *types.Transaction) (bool, types.Transactions) {
|
|||
// prevent getting into and invalid state. This is not something that should ever
|
||||
// happen but better to be self correcting than failing!
|
||||
func (l *txList) Ready(start uint64) types.Transactions {
|
||||
return l.txs.Ready(start)
|
||||
txs := l.txs.Ready(start)
|
||||
l.subTotalCost(txs)
|
||||
|
||||
return txs
|
||||
}
|
||||
|
||||
// Len returns the length of the transaction list.
|
||||
|
|
@ -416,13 +622,26 @@ func (l *txList) LastElement() *types.Transaction {
|
|||
return l.txs.LastElement()
|
||||
}
|
||||
|
||||
func (l *txList) Has(nonce uint64) bool {
|
||||
return l != nil && l.txs.items[nonce] != nil
|
||||
}
|
||||
|
||||
// subTotalCost subtracts the cost of the given transactions from the
|
||||
// total cost of all transactions.
|
||||
func (l *txList) subTotalCost(txs []*types.Transaction) {
|
||||
for _, tx := range txs {
|
||||
l.totalcost.Sub(l.totalcost, tx.Cost())
|
||||
}
|
||||
}
|
||||
|
||||
// priceHeap is a heap.Interface implementation over transactions for retrieving
|
||||
// price-sorted transactions to discard when the pool fills up. If baseFee is set
|
||||
// then the heap is sorted based on the effective tip based on the given base fee.
|
||||
// If baseFee is nil then the sorting is based on gasFeeCap.
|
||||
type priceHeap struct {
|
||||
baseFee *big.Int // heap should always be re-sorted after baseFee is changed
|
||||
baseFee *uint256.Int // heap should always be re-sorted after baseFee is changed
|
||||
list []*types.Transaction
|
||||
baseFeeMu sync.RWMutex
|
||||
}
|
||||
|
||||
func (h *priceHeap) Len() int { return len(h.list) }
|
||||
|
|
@ -440,16 +659,24 @@ func (h *priceHeap) Less(i, j int) bool {
|
|||
}
|
||||
|
||||
func (h *priceHeap) cmp(a, b *types.Transaction) int {
|
||||
h.baseFeeMu.RLock()
|
||||
|
||||
if h.baseFee != nil {
|
||||
// Compare effective tips if baseFee is specified
|
||||
if c := a.EffectiveGasTipCmp(b, h.baseFee); c != 0 {
|
||||
if c := a.EffectiveGasTipTxUintCmp(b, h.baseFee); c != 0 {
|
||||
h.baseFeeMu.RUnlock()
|
||||
|
||||
return c
|
||||
}
|
||||
}
|
||||
|
||||
h.baseFeeMu.RUnlock()
|
||||
|
||||
// Compare fee caps if baseFee is not specified or effective tips are equal
|
||||
if c := a.GasFeeCapCmp(b); c != 0 {
|
||||
return c
|
||||
}
|
||||
|
||||
// Compare tips if effective tips and fee caps are equal
|
||||
return a.GasTipCapCmp(b)
|
||||
}
|
||||
|
|
@ -629,7 +856,10 @@ func (l *txPricedList) Reheap() {
|
|||
|
||||
// SetBaseFee updates the base fee and triggers a re-heap. Note that Removed is not
|
||||
// necessary to call right before SetBaseFee when processing a new block.
|
||||
func (l *txPricedList) SetBaseFee(baseFee *big.Int) {
|
||||
func (l *txPricedList) SetBaseFee(baseFee *uint256.Int) {
|
||||
l.urgent.baseFeeMu.Lock()
|
||||
l.urgent.baseFee = baseFee
|
||||
l.urgent.baseFeeMu.Unlock()
|
||||
|
||||
l.Reheap()
|
||||
}
|
||||
|
|
|
|||
|
|
@ -17,10 +17,11 @@
|
|||
package core
|
||||
|
||||
import (
|
||||
"math/big"
|
||||
"math/rand"
|
||||
"testing"
|
||||
|
||||
"github.com/holiman/uint256"
|
||||
|
||||
"github.com/ethereum/go-ethereum/core/types"
|
||||
"github.com/ethereum/go-ethereum/crypto"
|
||||
)
|
||||
|
|
@ -59,11 +60,15 @@ func BenchmarkTxListAdd(b *testing.B) {
|
|||
for i := 0; i < len(txs); i++ {
|
||||
txs[i] = transaction(uint64(i), 0, key)
|
||||
}
|
||||
|
||||
// Insert the transactions in a random order
|
||||
priceLimit := big.NewInt(int64(DefaultTxPoolConfig.PriceLimit))
|
||||
priceLimit := uint256.NewInt(DefaultTxPoolConfig.PriceLimit)
|
||||
b.ResetTimer()
|
||||
b.ReportAllocs()
|
||||
|
||||
for i := 0; i < b.N; i++ {
|
||||
list := newTxList(true)
|
||||
|
||||
for _, v := range rand.Perm(len(txs)) {
|
||||
list.Add(txs[v], DefaultTxPoolConfig.PriceBump)
|
||||
list.Filter(priceLimit, DefaultTxPoolConfig.PriceBump)
|
||||
|
|
|
|||
964
core/tx_pool.go
964
core/tx_pool.go
File diff suppressed because it is too large
Load diff
1616
core/tx_pool_test.go
1616
core/tx_pool_test.go
File diff suppressed because it is too large
Load diff
229
core/txpool2_test.go
Normal file
229
core/txpool2_test.go
Normal file
|
|
@ -0,0 +1,229 @@
|
|||
// Copyright 2023 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 <http://www.gnu.org/licenses/>.
|
||||
package core
|
||||
|
||||
import (
|
||||
"crypto/ecdsa"
|
||||
"math/big"
|
||||
"testing"
|
||||
|
||||
"github.com/ethereum/go-ethereum/common"
|
||||
"github.com/ethereum/go-ethereum/core/rawdb"
|
||||
"github.com/ethereum/go-ethereum/core/state"
|
||||
"github.com/ethereum/go-ethereum/core/types"
|
||||
"github.com/ethereum/go-ethereum/crypto"
|
||||
"github.com/ethereum/go-ethereum/event"
|
||||
)
|
||||
|
||||
func pricedValuedTransaction(nonce uint64, value int64, gaslimit uint64, gasprice *big.Int, key *ecdsa.PrivateKey) *types.Transaction {
|
||||
tx, _ := types.SignTx(types.NewTransaction(nonce, common.Address{}, big.NewInt(value), gaslimit, gasprice, nil), types.HomesteadSigner{}, key)
|
||||
return tx
|
||||
}
|
||||
|
||||
func count(t *testing.T, pool *TxPool) (pending int, queued int) {
|
||||
t.Helper()
|
||||
|
||||
pending, queued = pool.stats()
|
||||
|
||||
if err := validateTxPoolInternals(pool); err != nil {
|
||||
t.Fatalf("pool internal state corrupted: %v", err)
|
||||
}
|
||||
|
||||
return pending, queued
|
||||
}
|
||||
|
||||
func fillPool(t *testing.T, pool *TxPool) {
|
||||
t.Helper()
|
||||
// Create a number of test accounts, fund them and make transactions
|
||||
executableTxs := types.Transactions{}
|
||||
nonExecutableTxs := types.Transactions{}
|
||||
|
||||
for i := 0; i < 384; i++ {
|
||||
key, _ := crypto.GenerateKey()
|
||||
pool.currentState.AddBalance(crypto.PubkeyToAddress(key.PublicKey), big.NewInt(10000000000))
|
||||
// Add executable ones
|
||||
for j := 0; j < int(pool.config.AccountSlots); j++ {
|
||||
executableTxs = append(executableTxs, pricedTransaction(uint64(j), 100000, big.NewInt(300), key))
|
||||
}
|
||||
}
|
||||
// Import the batch and verify that limits have been enforced
|
||||
pool.AddRemotesSync(executableTxs)
|
||||
pool.AddRemotesSync(nonExecutableTxs)
|
||||
pending, queued := pool.Stats()
|
||||
slots := pool.all.Slots()
|
||||
// sanity-check that the test prerequisites are ok (pending full)
|
||||
if have, want := pending, slots; have != want {
|
||||
t.Fatalf("have %d, want %d", have, want)
|
||||
}
|
||||
|
||||
if have, want := queued, 0; have != want {
|
||||
t.Fatalf("have %d, want %d", have, want)
|
||||
}
|
||||
|
||||
t.Logf("pool.config: GlobalSlots=%d, GlobalQueue=%d\n", pool.config.GlobalSlots, pool.config.GlobalQueue)
|
||||
t.Logf("pending: %d queued: %d, all: %d\n", pending, queued, slots)
|
||||
}
|
||||
|
||||
// Tests that if a batch high-priced of non-executables arrive, they do not kick out
|
||||
// executable transactions
|
||||
func TestTransactionFutureAttack(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
// Create the pool to test the limit enforcement with
|
||||
statedb, _ := state.New(common.Hash{}, state.NewDatabase(rawdb.NewMemoryDatabase()), nil)
|
||||
blockchain := &testBlockChain{1000000, statedb, new(event.Feed)}
|
||||
config := testTxPoolConfig
|
||||
config.GlobalQueue = 100
|
||||
config.GlobalSlots = 100
|
||||
pool := NewTxPool(config, eip1559Config, blockchain)
|
||||
|
||||
defer pool.Stop()
|
||||
fillPool(t, pool)
|
||||
pending, _ := pool.Stats()
|
||||
// Now, future transaction attack starts, let's add a bunch of expensive non-executables, and see if the pending-count drops
|
||||
{
|
||||
key, _ := crypto.GenerateKey()
|
||||
pool.currentState.AddBalance(crypto.PubkeyToAddress(key.PublicKey), big.NewInt(100000000000))
|
||||
futureTxs := types.Transactions{}
|
||||
for j := 0; j < int(pool.config.GlobalSlots+pool.config.GlobalQueue); j++ {
|
||||
futureTxs = append(futureTxs, pricedTransaction(1000+uint64(j), 100000, big.NewInt(500), key))
|
||||
}
|
||||
for i := 0; i < 5; i++ {
|
||||
pool.AddRemotesSync(futureTxs)
|
||||
newPending, newQueued := count(t, pool)
|
||||
t.Logf("pending: %d queued: %d, all: %d\n", newPending, newQueued, pool.all.Slots())
|
||||
}
|
||||
}
|
||||
|
||||
newPending, _ := pool.Stats()
|
||||
// Pending should not have been touched
|
||||
if have, want := newPending, pending; have < want {
|
||||
t.Errorf("wrong pending-count, have %d, want %d (GlobalSlots: %d)",
|
||||
have, want, pool.config.GlobalSlots)
|
||||
}
|
||||
}
|
||||
|
||||
// Tests that if a batch high-priced of non-executables arrive, they do not kick out
|
||||
// executable transactions
|
||||
func TestTransactionFuture1559(t *testing.T) {
|
||||
t.Parallel()
|
||||
// Create the pool to test the pricing enforcement with
|
||||
statedb, _ := state.New(common.Hash{}, state.NewDatabase(rawdb.NewMemoryDatabase()), nil)
|
||||
blockchain := &testBlockChain{1000000, statedb, new(event.Feed)}
|
||||
pool := NewTxPool(testTxPoolConfig, eip1559Config, blockchain)
|
||||
|
||||
defer pool.Stop()
|
||||
|
||||
// Create a number of test accounts, fund them and make transactions
|
||||
fillPool(t, pool)
|
||||
pending, _ := pool.Stats()
|
||||
|
||||
// Now, future transaction attack starts, let's add a bunch of expensive non-executables, and see if the pending-count drops
|
||||
{
|
||||
key, _ := crypto.GenerateKey()
|
||||
pool.currentState.AddBalance(crypto.PubkeyToAddress(key.PublicKey), big.NewInt(100000000000))
|
||||
futureTxs := types.Transactions{}
|
||||
for j := 0; j < int(pool.config.GlobalSlots+pool.config.GlobalQueue); j++ {
|
||||
futureTxs = append(futureTxs, dynamicFeeTx(1000+uint64(j), 100000, big.NewInt(200), big.NewInt(101), key))
|
||||
}
|
||||
pool.AddRemotesSync(futureTxs)
|
||||
}
|
||||
|
||||
newPending, _ := pool.Stats()
|
||||
// Pending should not have been touched
|
||||
if have, want := newPending, pending; have != want {
|
||||
t.Errorf("Wrong pending-count, have %d, want %d (GlobalSlots: %d)",
|
||||
have, want, pool.config.GlobalSlots)
|
||||
}
|
||||
}
|
||||
|
||||
// Tests that if a batch of balance-overdraft txs arrive, they do not kick out
|
||||
// executable transactions
|
||||
func TestTransactionZAttack(t *testing.T) {
|
||||
t.Parallel()
|
||||
// Create the pool to test the pricing enforcement with
|
||||
statedb, _ := state.New(common.Hash{}, state.NewDatabase(rawdb.NewMemoryDatabase()), nil)
|
||||
blockchain := &testBlockChain{1000000, statedb, new(event.Feed)}
|
||||
pool := NewTxPool(testTxPoolConfig, eip1559Config, blockchain)
|
||||
|
||||
defer pool.Stop()
|
||||
|
||||
// Create a number of test accounts, fund them and make transactions
|
||||
fillPool(t, pool)
|
||||
|
||||
countInvalidPending := func() int {
|
||||
t.Helper()
|
||||
|
||||
var ivpendingNum int
|
||||
|
||||
pendingtxs, _ := pool.Content()
|
||||
|
||||
for account, txs := range pendingtxs {
|
||||
cur_balance := new(big.Int).Set(pool.currentState.GetBalance(account))
|
||||
for _, tx := range txs {
|
||||
if cur_balance.Cmp(tx.Value()) <= 0 {
|
||||
ivpendingNum++
|
||||
} else {
|
||||
cur_balance.Sub(cur_balance, tx.Value())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if err := validateTxPoolInternals(pool); err != nil {
|
||||
t.Fatalf("pool internal state corrupted: %v", err)
|
||||
}
|
||||
|
||||
return ivpendingNum
|
||||
}
|
||||
ivPending := countInvalidPending()
|
||||
t.Logf("invalid pending: %d\n", ivPending)
|
||||
|
||||
// Now, DETER-Z attack starts, let's add a bunch of expensive non-executables (from N accounts) along with balance-overdraft txs (from one account), and see if the pending-count drops
|
||||
for j := 0; j < int(pool.config.GlobalQueue); j++ {
|
||||
futureTxs := types.Transactions{}
|
||||
key, _ := crypto.GenerateKey()
|
||||
pool.currentState.AddBalance(crypto.PubkeyToAddress(key.PublicKey), big.NewInt(100000000000))
|
||||
futureTxs = append(futureTxs, pricedTransaction(1000+uint64(j), 21000, big.NewInt(500), key))
|
||||
pool.AddRemotesSync(futureTxs)
|
||||
}
|
||||
|
||||
overDraftTxs := types.Transactions{}
|
||||
{
|
||||
key, _ := crypto.GenerateKey()
|
||||
pool.currentState.AddBalance(crypto.PubkeyToAddress(key.PublicKey), big.NewInt(100000000000))
|
||||
for j := 0; j < int(pool.config.GlobalSlots); j++ {
|
||||
overDraftTxs = append(overDraftTxs, pricedValuedTransaction(uint64(j), 60000000000, 21000, big.NewInt(500), key))
|
||||
}
|
||||
}
|
||||
pool.AddRemotesSync(overDraftTxs)
|
||||
pool.AddRemotesSync(overDraftTxs)
|
||||
pool.AddRemotesSync(overDraftTxs)
|
||||
pool.AddRemotesSync(overDraftTxs)
|
||||
pool.AddRemotesSync(overDraftTxs)
|
||||
|
||||
newPending, newQueued := count(t, pool)
|
||||
newIvPending := countInvalidPending()
|
||||
|
||||
t.Logf("pool.all.Slots(): %d\n", pool.all.Slots())
|
||||
t.Logf("pending: %d queued: %d, all: %d\n", newPending, newQueued, pool.all.Slots())
|
||||
t.Logf("invalid pending: %d\n", newIvPending)
|
||||
|
||||
// Pending should not have been touched
|
||||
if newIvPending != ivPending {
|
||||
t.Errorf("Wrong invalid pending-count, have %d, want %d (GlobalSlots: %d, queued: %d)",
|
||||
newIvPending, ivPending, pool.config.GlobalSlots, newQueued)
|
||||
}
|
||||
}
|
||||
|
|
@ -19,6 +19,8 @@ package types
|
|||
import (
|
||||
"math/big"
|
||||
|
||||
"github.com/holiman/uint256"
|
||||
|
||||
"github.com/ethereum/go-ethereum/common"
|
||||
)
|
||||
|
||||
|
|
@ -47,6 +49,7 @@ type AccessListTx struct {
|
|||
ChainID *big.Int // destination chain ID
|
||||
Nonce uint64 // nonce of sender account
|
||||
GasPrice *big.Int // wei per gas
|
||||
gasPriceUint256 *uint256.Int // wei per gas
|
||||
Gas uint64 // gas limit
|
||||
To *common.Address `rlp:"nil"` // nil means contract creation
|
||||
Value *big.Int // wei amount
|
||||
|
|
@ -80,6 +83,12 @@ func (tx *AccessListTx) copy() TxData {
|
|||
}
|
||||
if tx.GasPrice != nil {
|
||||
cpy.GasPrice.Set(tx.GasPrice)
|
||||
|
||||
if cpy.gasPriceUint256 != nil {
|
||||
cpy.gasPriceUint256.Set(tx.gasPriceUint256)
|
||||
} else {
|
||||
cpy.gasPriceUint256, _ = uint256.FromBig(tx.GasPrice)
|
||||
}
|
||||
}
|
||||
if tx.V != nil {
|
||||
cpy.V.Set(tx.V)
|
||||
|
|
@ -100,8 +109,36 @@ func (tx *AccessListTx) accessList() AccessList { return tx.AccessList }
|
|||
func (tx *AccessListTx) data() []byte { return tx.Data }
|
||||
func (tx *AccessListTx) gas() uint64 { return tx.Gas }
|
||||
func (tx *AccessListTx) gasPrice() *big.Int { return tx.GasPrice }
|
||||
func (tx *AccessListTx) gasPriceU256() *uint256.Int {
|
||||
if tx.gasPriceUint256 != nil {
|
||||
return tx.gasPriceUint256
|
||||
}
|
||||
|
||||
tx.gasPriceUint256, _ = uint256.FromBig(tx.GasPrice)
|
||||
|
||||
return tx.gasPriceUint256
|
||||
}
|
||||
|
||||
func (tx *AccessListTx) gasTipCap() *big.Int { return tx.GasPrice }
|
||||
func (tx *AccessListTx) gasTipCapU256() *uint256.Int {
|
||||
if tx.gasPriceUint256 != nil {
|
||||
return tx.gasPriceUint256
|
||||
}
|
||||
|
||||
tx.gasPriceUint256, _ = uint256.FromBig(tx.GasPrice)
|
||||
|
||||
return tx.gasPriceUint256
|
||||
}
|
||||
func (tx *AccessListTx) gasFeeCap() *big.Int { return tx.GasPrice }
|
||||
func (tx *AccessListTx) gasFeeCapU256() *uint256.Int {
|
||||
if tx.gasPriceUint256 != nil {
|
||||
return tx.gasPriceUint256
|
||||
}
|
||||
|
||||
tx.gasPriceUint256, _ = uint256.FromBig(tx.GasPrice)
|
||||
|
||||
return tx.gasPriceUint256
|
||||
}
|
||||
func (tx *AccessListTx) value() *big.Int { return tx.Value }
|
||||
func (tx *AccessListTx) nonce() uint64 { return tx.Nonce }
|
||||
func (tx *AccessListTx) to() *common.Address { return tx.To }
|
||||
|
|
|
|||
|
|
@ -19,6 +19,8 @@ package types
|
|||
import (
|
||||
"math/big"
|
||||
|
||||
"github.com/holiman/uint256"
|
||||
|
||||
"github.com/ethereum/go-ethereum/common"
|
||||
)
|
||||
|
||||
|
|
@ -26,7 +28,9 @@ type DynamicFeeTx struct {
|
|||
ChainID *big.Int
|
||||
Nonce uint64
|
||||
GasTipCap *big.Int // a.k.a. maxPriorityFeePerGas
|
||||
gasTipCapUint256 *uint256.Int // a.k.a. maxPriorityFeePerGas
|
||||
GasFeeCap *big.Int // a.k.a. maxFeePerGas
|
||||
gasFeeCapUint256 *uint256.Int // a.k.a. maxFeePerGas
|
||||
Gas uint64
|
||||
To *common.Address `rlp:"nil"` // nil means contract creation
|
||||
Value *big.Int
|
||||
|
|
@ -65,9 +69,21 @@ func (tx *DynamicFeeTx) copy() TxData {
|
|||
}
|
||||
if tx.GasTipCap != nil {
|
||||
cpy.GasTipCap.Set(tx.GasTipCap)
|
||||
|
||||
if cpy.gasTipCapUint256 != nil {
|
||||
cpy.gasTipCapUint256.Set(tx.gasTipCapUint256)
|
||||
} else {
|
||||
cpy.gasTipCapUint256, _ = uint256.FromBig(tx.GasTipCap)
|
||||
}
|
||||
}
|
||||
if tx.GasFeeCap != nil {
|
||||
cpy.GasFeeCap.Set(tx.GasFeeCap)
|
||||
|
||||
if cpy.gasFeeCapUint256 != nil {
|
||||
cpy.gasFeeCapUint256.Set(tx.gasFeeCapUint256)
|
||||
} else {
|
||||
cpy.gasFeeCapUint256, _ = uint256.FromBig(tx.GasFeeCap)
|
||||
}
|
||||
}
|
||||
if tx.V != nil {
|
||||
cpy.V.Set(tx.V)
|
||||
|
|
@ -88,8 +104,35 @@ func (tx *DynamicFeeTx) accessList() AccessList { return tx.AccessList }
|
|||
func (tx *DynamicFeeTx) data() []byte { return tx.Data }
|
||||
func (tx *DynamicFeeTx) gas() uint64 { return tx.Gas }
|
||||
func (tx *DynamicFeeTx) gasFeeCap() *big.Int { return tx.GasFeeCap }
|
||||
func (tx *DynamicFeeTx) gasFeeCapU256() *uint256.Int {
|
||||
if tx.gasFeeCapUint256 != nil {
|
||||
return tx.gasFeeCapUint256
|
||||
}
|
||||
|
||||
tx.gasFeeCapUint256, _ = uint256.FromBig(tx.GasFeeCap)
|
||||
|
||||
return tx.gasFeeCapUint256
|
||||
}
|
||||
func (tx *DynamicFeeTx) gasTipCap() *big.Int { return tx.GasTipCap }
|
||||
func (tx *DynamicFeeTx) gasTipCapU256() *uint256.Int {
|
||||
if tx.gasTipCapUint256 != nil {
|
||||
return tx.gasTipCapUint256
|
||||
}
|
||||
|
||||
tx.gasTipCapUint256, _ = uint256.FromBig(tx.GasTipCap)
|
||||
|
||||
return tx.gasTipCapUint256
|
||||
}
|
||||
func (tx *DynamicFeeTx) gasPrice() *big.Int { return tx.GasFeeCap }
|
||||
func (tx *DynamicFeeTx) gasPriceU256() *uint256.Int {
|
||||
if tx.gasFeeCapUint256 != nil {
|
||||
return tx.gasTipCapUint256
|
||||
}
|
||||
|
||||
tx.gasFeeCapUint256, _ = uint256.FromBig(tx.GasFeeCap)
|
||||
|
||||
return tx.gasFeeCapUint256
|
||||
}
|
||||
func (tx *DynamicFeeTx) value() *big.Int { return tx.Value }
|
||||
func (tx *DynamicFeeTx) nonce() uint64 { return tx.Nonce }
|
||||
func (tx *DynamicFeeTx) to() *common.Address { return tx.To }
|
||||
|
|
|
|||
|
|
@ -19,6 +19,8 @@ package types
|
|||
import (
|
||||
"math/big"
|
||||
|
||||
"github.com/holiman/uint256"
|
||||
|
||||
"github.com/ethereum/go-ethereum/common"
|
||||
)
|
||||
|
||||
|
|
@ -26,6 +28,7 @@ import (
|
|||
type LegacyTx struct {
|
||||
Nonce uint64 // nonce of sender account
|
||||
GasPrice *big.Int // wei per gas
|
||||
gasPriceUint256 *uint256.Int // wei per gas
|
||||
Gas uint64 // gas limit
|
||||
To *common.Address `rlp:"nil"` // nil means contract creation
|
||||
Value *big.Int // wei amount
|
||||
|
|
@ -77,6 +80,12 @@ func (tx *LegacyTx) copy() TxData {
|
|||
}
|
||||
if tx.GasPrice != nil {
|
||||
cpy.GasPrice.Set(tx.GasPrice)
|
||||
|
||||
if cpy.gasPriceUint256 != nil {
|
||||
cpy.gasPriceUint256.Set(tx.gasPriceUint256)
|
||||
} else {
|
||||
cpy.gasPriceUint256, _ = uint256.FromBig(tx.GasPrice)
|
||||
}
|
||||
}
|
||||
if tx.V != nil {
|
||||
cpy.V.Set(tx.V)
|
||||
|
|
@ -97,8 +106,35 @@ func (tx *LegacyTx) accessList() AccessList { return nil }
|
|||
func (tx *LegacyTx) data() []byte { return tx.Data }
|
||||
func (tx *LegacyTx) gas() uint64 { return tx.Gas }
|
||||
func (tx *LegacyTx) gasPrice() *big.Int { return tx.GasPrice }
|
||||
func (tx *LegacyTx) gasPriceU256() *uint256.Int {
|
||||
if tx.gasPriceUint256 != nil {
|
||||
return tx.gasPriceUint256
|
||||
}
|
||||
|
||||
tx.gasPriceUint256, _ = uint256.FromBig(tx.GasPrice)
|
||||
|
||||
return tx.gasPriceUint256
|
||||
}
|
||||
func (tx *LegacyTx) gasTipCap() *big.Int { return tx.GasPrice }
|
||||
func (tx *LegacyTx) gasTipCapU256() *uint256.Int {
|
||||
if tx.gasPriceUint256 != nil {
|
||||
return tx.gasPriceUint256
|
||||
}
|
||||
|
||||
tx.gasPriceUint256, _ = uint256.FromBig(tx.GasPrice)
|
||||
|
||||
return tx.gasPriceUint256
|
||||
}
|
||||
func (tx *LegacyTx) gasFeeCap() *big.Int { return tx.GasPrice }
|
||||
func (tx *LegacyTx) gasFeeCapU256() *uint256.Int {
|
||||
if tx.gasPriceUint256 != nil {
|
||||
return tx.gasPriceUint256
|
||||
}
|
||||
|
||||
tx.gasPriceUint256, _ = uint256.FromBig(tx.GasPrice)
|
||||
|
||||
return tx.gasPriceUint256
|
||||
}
|
||||
func (tx *LegacyTx) value() *big.Int { return tx.Value }
|
||||
func (tx *LegacyTx) nonce() uint64 { return tx.Nonce }
|
||||
func (tx *LegacyTx) to() *common.Address { return tx.To }
|
||||
|
|
|
|||
|
|
@ -25,6 +25,8 @@ import (
|
|||
"sync/atomic"
|
||||
"time"
|
||||
|
||||
"github.com/holiman/uint256"
|
||||
|
||||
"github.com/ethereum/go-ethereum/common"
|
||||
"github.com/ethereum/go-ethereum/common/math"
|
||||
"github.com/ethereum/go-ethereum/crypto"
|
||||
|
|
@ -53,9 +55,9 @@ type Transaction struct {
|
|||
time time.Time // Time first seen locally (spam avoidance)
|
||||
|
||||
// caches
|
||||
hash atomic.Value
|
||||
size atomic.Value
|
||||
from atomic.Value
|
||||
hash atomic.Pointer[common.Hash]
|
||||
size atomic.Pointer[common.StorageSize]
|
||||
from atomic.Pointer[sigCache]
|
||||
}
|
||||
|
||||
// NewTx creates a new transaction.
|
||||
|
|
@ -77,8 +79,11 @@ type TxData interface {
|
|||
data() []byte
|
||||
gas() uint64
|
||||
gasPrice() *big.Int
|
||||
gasPriceU256() *uint256.Int
|
||||
gasTipCap() *big.Int
|
||||
gasTipCapU256() *uint256.Int
|
||||
gasFeeCap() *big.Int
|
||||
gasFeeCapU256() *uint256.Int
|
||||
value() *big.Int
|
||||
nonce() uint64
|
||||
to() *common.Address
|
||||
|
|
@ -194,7 +199,8 @@ func (tx *Transaction) setDecoded(inner TxData, size int) {
|
|||
tx.inner = inner
|
||||
tx.time = time.Now()
|
||||
if size > 0 {
|
||||
tx.size.Store(common.StorageSize(size))
|
||||
v := float64(size)
|
||||
tx.size.Store((*common.StorageSize)(&v))
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -266,15 +272,22 @@ func (tx *Transaction) Gas() uint64 { return tx.inner.gas() }
|
|||
|
||||
// GasPrice returns the gas price of the transaction.
|
||||
func (tx *Transaction) GasPrice() *big.Int { return new(big.Int).Set(tx.inner.gasPrice()) }
|
||||
func (tx *Transaction) GasPriceRef() *big.Int { return tx.inner.gasPrice() }
|
||||
func (tx *Transaction) GasPriceUint() *uint256.Int { return tx.inner.gasPriceU256() }
|
||||
|
||||
// GasTipCap returns the gasTipCap per gas of the transaction.
|
||||
func (tx *Transaction) GasTipCap() *big.Int { return new(big.Int).Set(tx.inner.gasTipCap()) }
|
||||
func (tx *Transaction) GasTipCapRef() *big.Int { return tx.inner.gasTipCap() }
|
||||
func (tx *Transaction) GasTipCapUint() *uint256.Int { return tx.inner.gasTipCapU256() }
|
||||
|
||||
// GasFeeCap returns the fee cap per gas of the transaction.
|
||||
func (tx *Transaction) GasFeeCap() *big.Int { return new(big.Int).Set(tx.inner.gasFeeCap()) }
|
||||
func (tx *Transaction) GasFeeCapRef() *big.Int { return tx.inner.gasFeeCap() }
|
||||
func (tx *Transaction) GasFeeCapUint() *uint256.Int { return tx.inner.gasFeeCapU256() }
|
||||
|
||||
// Value returns the ether amount of the transaction.
|
||||
func (tx *Transaction) Value() *big.Int { return new(big.Int).Set(tx.inner.value()) }
|
||||
func (tx *Transaction) ValueRef() *big.Int { return tx.inner.value() }
|
||||
|
||||
// Nonce returns the sender account nonce of the transaction.
|
||||
func (tx *Transaction) Nonce() uint64 { return tx.inner.nonce() }
|
||||
|
|
@ -287,9 +300,19 @@ func (tx *Transaction) To() *common.Address {
|
|||
|
||||
// Cost returns gas * gasPrice + value.
|
||||
func (tx *Transaction) Cost() *big.Int {
|
||||
total := new(big.Int).Mul(tx.GasPrice(), new(big.Int).SetUint64(tx.Gas()))
|
||||
total.Add(total, tx.Value())
|
||||
return total
|
||||
gasPrice, _ := uint256.FromBig(tx.GasPriceRef())
|
||||
gasPrice.Mul(gasPrice, uint256.NewInt(tx.Gas()))
|
||||
value, _ := uint256.FromBig(tx.ValueRef())
|
||||
|
||||
return gasPrice.Add(gasPrice, value).ToBig()
|
||||
}
|
||||
|
||||
func (tx *Transaction) CostUint() *uint256.Int {
|
||||
gasPrice, _ := uint256.FromBig(tx.GasPriceRef())
|
||||
gasPrice.Mul(gasPrice, uint256.NewInt(tx.Gas()))
|
||||
value, _ := uint256.FromBig(tx.ValueRef())
|
||||
|
||||
return gasPrice.Add(gasPrice, value)
|
||||
}
|
||||
|
||||
// RawSignatureValues returns the V, R, S signature values of the transaction.
|
||||
|
|
@ -303,11 +326,18 @@ func (tx *Transaction) GasFeeCapCmp(other *Transaction) int {
|
|||
return tx.inner.gasFeeCap().Cmp(other.inner.gasFeeCap())
|
||||
}
|
||||
|
||||
// GasFeeCapIntCmp compares the fee cap of the transaction against the given fee cap.
|
||||
func (tx *Transaction) GasFeeCapIntCmp(other *big.Int) int {
|
||||
return tx.inner.gasFeeCap().Cmp(other)
|
||||
}
|
||||
|
||||
func (tx *Transaction) GasFeeCapUIntCmp(other *uint256.Int) int {
|
||||
return tx.inner.gasFeeCapU256().Cmp(other)
|
||||
}
|
||||
|
||||
func (tx *Transaction) GasFeeCapUIntLt(other *uint256.Int) bool {
|
||||
return tx.inner.gasFeeCapU256().Lt(other)
|
||||
}
|
||||
|
||||
// GasTipCapCmp compares the gasTipCap of two transactions.
|
||||
func (tx *Transaction) GasTipCapCmp(other *Transaction) int {
|
||||
return tx.inner.gasTipCap().Cmp(other.inner.gasTipCap())
|
||||
|
|
@ -318,6 +348,14 @@ func (tx *Transaction) GasTipCapIntCmp(other *big.Int) int {
|
|||
return tx.inner.gasTipCap().Cmp(other)
|
||||
}
|
||||
|
||||
func (tx *Transaction) GasTipCapUIntCmp(other *uint256.Int) int {
|
||||
return tx.inner.gasTipCapU256().Cmp(other)
|
||||
}
|
||||
|
||||
func (tx *Transaction) GasTipCapUIntLt(other *uint256.Int) bool {
|
||||
return tx.inner.gasTipCapU256().Lt(other)
|
||||
}
|
||||
|
||||
// EffectiveGasTip returns the effective miner gasTipCap for the given base fee.
|
||||
// Note: if the effective gasTipCap is negative, this method returns both error
|
||||
// the actual negative value, _and_ ErrGasFeeCapTooLow
|
||||
|
|
@ -356,10 +394,73 @@ func (tx *Transaction) EffectiveGasTipIntCmp(other *big.Int, baseFee *big.Int) i
|
|||
return tx.EffectiveGasTipValue(baseFee).Cmp(other)
|
||||
}
|
||||
|
||||
func (tx *Transaction) EffectiveGasTipUintCmp(other *uint256.Int, baseFee *uint256.Int) int {
|
||||
if baseFee == nil {
|
||||
return tx.GasTipCapUIntCmp(other)
|
||||
}
|
||||
|
||||
return tx.EffectiveGasTipValueUint(baseFee).Cmp(other)
|
||||
}
|
||||
|
||||
func (tx *Transaction) EffectiveGasTipUintLt(other *uint256.Int, baseFee *uint256.Int) bool {
|
||||
if baseFee == nil {
|
||||
return tx.GasTipCapUIntLt(other)
|
||||
}
|
||||
|
||||
return tx.EffectiveGasTipValueUint(baseFee).Lt(other)
|
||||
}
|
||||
|
||||
func (tx *Transaction) EffectiveGasTipTxUintCmp(other *Transaction, baseFee *uint256.Int) int {
|
||||
if baseFee == nil {
|
||||
return tx.inner.gasTipCapU256().Cmp(other.inner.gasTipCapU256())
|
||||
}
|
||||
|
||||
return tx.EffectiveGasTipValueUint(baseFee).Cmp(other.EffectiveGasTipValueUint(baseFee))
|
||||
}
|
||||
|
||||
func (tx *Transaction) EffectiveGasTipValueUint(baseFee *uint256.Int) *uint256.Int {
|
||||
effectiveTip, _ := tx.EffectiveGasTipUnit(baseFee)
|
||||
return effectiveTip
|
||||
}
|
||||
|
||||
func (tx *Transaction) EffectiveGasTipUnit(baseFee *uint256.Int) (*uint256.Int, error) {
|
||||
if baseFee == nil {
|
||||
return tx.GasFeeCapUint(), nil
|
||||
}
|
||||
|
||||
var err error
|
||||
|
||||
gasFeeCap := tx.GasFeeCapUint().Clone()
|
||||
|
||||
if gasFeeCap.Lt(baseFee) {
|
||||
err = ErrGasFeeCapTooLow
|
||||
}
|
||||
|
||||
gasTipCapUint := tx.GasTipCapUint()
|
||||
|
||||
if gasFeeCap.Lt(gasTipCapUint) {
|
||||
return gasFeeCap, err
|
||||
}
|
||||
|
||||
if gasFeeCap.Lt(gasTipCapUint) && baseFee.IsZero() {
|
||||
return gasFeeCap, err
|
||||
}
|
||||
|
||||
gasFeeCap.Sub(gasFeeCap, baseFee)
|
||||
|
||||
if gasFeeCap.Gt(gasTipCapUint) || gasFeeCap.Eq(gasTipCapUint) {
|
||||
gasFeeCap.Add(gasFeeCap, baseFee)
|
||||
|
||||
return gasTipCapUint, err
|
||||
}
|
||||
|
||||
return gasFeeCap, err
|
||||
}
|
||||
|
||||
// Hash returns the transaction hash.
|
||||
func (tx *Transaction) Hash() common.Hash {
|
||||
if hash := tx.hash.Load(); hash != nil {
|
||||
return hash.(common.Hash)
|
||||
return *hash
|
||||
}
|
||||
|
||||
var h common.Hash
|
||||
|
|
@ -368,7 +469,9 @@ func (tx *Transaction) Hash() common.Hash {
|
|||
} else {
|
||||
h = prefixedRlpHash(tx.Type(), tx.inner)
|
||||
}
|
||||
tx.hash.Store(h)
|
||||
|
||||
tx.hash.Store(&h)
|
||||
|
||||
return h
|
||||
}
|
||||
|
||||
|
|
@ -376,11 +479,14 @@ func (tx *Transaction) Hash() common.Hash {
|
|||
// encoding and returning it, or returning a previously cached value.
|
||||
func (tx *Transaction) Size() common.StorageSize {
|
||||
if size := tx.size.Load(); size != nil {
|
||||
return size.(common.StorageSize)
|
||||
return *size
|
||||
}
|
||||
|
||||
c := writeCounter(0)
|
||||
|
||||
rlp.Encode(&c, &tx.inner)
|
||||
tx.size.Store(common.StorageSize(c))
|
||||
tx.size.Store((*common.StorageSize)(&c))
|
||||
|
||||
return common.StorageSize(c)
|
||||
}
|
||||
|
||||
|
|
@ -444,14 +550,14 @@ func (s TxByNonce) Swap(i, j int) { s[i], s[j] = s[j], s[i] }
|
|||
// TxWithMinerFee wraps a transaction with its gas price or effective miner gasTipCap
|
||||
type TxWithMinerFee struct {
|
||||
tx *Transaction
|
||||
minerFee *big.Int
|
||||
minerFee *uint256.Int
|
||||
}
|
||||
|
||||
// NewTxWithMinerFee creates a wrapped transaction, calculating the effective
|
||||
// miner gasTipCap if a base fee is provided.
|
||||
// Returns error in case of a negative effective miner gasTipCap.
|
||||
func NewTxWithMinerFee(tx *Transaction, baseFee *big.Int) (*TxWithMinerFee, error) {
|
||||
minerFee, err := tx.EffectiveGasTip(baseFee)
|
||||
func NewTxWithMinerFee(tx *Transaction, baseFee *uint256.Int) (*TxWithMinerFee, error) {
|
||||
minerFee, err := tx.EffectiveGasTipUnit(baseFee)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
|
@ -496,7 +602,7 @@ type TransactionsByPriceAndNonce struct {
|
|||
txs map[common.Address]Transactions // Per account nonce-sorted list of transactions
|
||||
heads TxByPriceAndTime // Next transaction for each unique account (price heap)
|
||||
signer Signer // Signer for the set of transactions
|
||||
baseFee *big.Int // Current base fee
|
||||
baseFee *uint256.Int // Current base fee
|
||||
}
|
||||
|
||||
// NewTransactionsByPriceAndNonce creates a transaction set that can retrieve
|
||||
|
|
@ -504,6 +610,7 @@ type TransactionsByPriceAndNonce struct {
|
|||
//
|
||||
// Note, the input map is reowned so the caller should not interact any more with
|
||||
// if after providing it to the constructor.
|
||||
/*
|
||||
func NewTransactionsByPriceAndNonce(signer Signer, txs map[common.Address]Transactions, baseFee *big.Int) *TransactionsByPriceAndNonce {
|
||||
// Initialize a price and received time based heap with the head transactions
|
||||
heads := make(TxByPriceAndTime, 0, len(txs))
|
||||
|
|
@ -524,6 +631,39 @@ func NewTransactionsByPriceAndNonce(signer Signer, txs map[common.Address]Transa
|
|||
}
|
||||
heap.Init(&heads)
|
||||
|
||||
// Assemble and return the transaction set
|
||||
return &TransactionsByPriceAndNonce{
|
||||
txs: txs,
|
||||
heads: heads,
|
||||
signer: signer,
|
||||
baseFee: baseFee,
|
||||
}
|
||||
}*/
|
||||
|
||||
func NewTransactionsByPriceAndNonce(signer Signer, txs map[common.Address]Transactions, baseFee *uint256.Int) *TransactionsByPriceAndNonce {
|
||||
// Initialize a price and received time based heap with the head transactions
|
||||
heads := make(TxByPriceAndTime, 0, len(txs))
|
||||
|
||||
for from, accTxs := range txs {
|
||||
if len(accTxs) == 0 {
|
||||
continue
|
||||
}
|
||||
|
||||
acc, _ := Sender(signer, accTxs[0])
|
||||
wrapped, err := NewTxWithMinerFee(accTxs[0], baseFee)
|
||||
|
||||
// Remove transaction if sender doesn't match from, or if wrapping fails.
|
||||
if acc != from || err != nil {
|
||||
delete(txs, from)
|
||||
continue
|
||||
}
|
||||
|
||||
heads = append(heads, wrapped)
|
||||
txs[from] = accTxs[1:]
|
||||
}
|
||||
|
||||
heap.Init(&heads)
|
||||
|
||||
// Assemble and return the transaction set
|
||||
return &TransactionsByPriceAndNonce{
|
||||
txs: txs,
|
||||
|
|
|
|||
|
|
@ -130,12 +130,11 @@ func MustSignNewTx(prv *ecdsa.PrivateKey, s Signer, txdata TxData) *Transaction
|
|||
// not match the signer used in the current call.
|
||||
func Sender(signer Signer, tx *Transaction) (common.Address, error) {
|
||||
if sc := tx.from.Load(); sc != nil {
|
||||
sigCache := sc.(sigCache)
|
||||
// If the signer used to derive from in a previous
|
||||
// call is not the same as used current, invalidate
|
||||
// the cache.
|
||||
if sigCache.signer.Equal(signer) {
|
||||
return sigCache.from, nil
|
||||
if sc.signer.Equal(signer) {
|
||||
return sc.from, nil
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -143,7 +142,9 @@ func Sender(signer Signer, tx *Transaction) (common.Address, error) {
|
|||
if err != nil {
|
||||
return common.Address{}, err
|
||||
}
|
||||
tx.from.Store(sigCache{signer: signer, from: addr})
|
||||
|
||||
tx.from.Store(&sigCache{signer: signer, from: addr})
|
||||
|
||||
return addr, nil
|
||||
}
|
||||
|
||||
|
|
@ -461,10 +462,10 @@ func (fs FrontierSigner) SignatureValues(tx *Transaction, sig []byte) (r, s, v *
|
|||
func (fs FrontierSigner) Hash(tx *Transaction) common.Hash {
|
||||
return rlpHash([]interface{}{
|
||||
tx.Nonce(),
|
||||
tx.GasPrice(),
|
||||
tx.GasPriceRef(),
|
||||
tx.Gas(),
|
||||
tx.To(),
|
||||
tx.Value(),
|
||||
tx.ValueRef(),
|
||||
tx.Data(),
|
||||
})
|
||||
}
|
||||
|
|
|
|||
|
|
@ -27,7 +27,10 @@ import (
|
|||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/holiman/uint256"
|
||||
|
||||
"github.com/ethereum/go-ethereum/common"
|
||||
cmath "github.com/ethereum/go-ethereum/common/math"
|
||||
"github.com/ethereum/go-ethereum/crypto"
|
||||
"github.com/ethereum/go-ethereum/rlp"
|
||||
)
|
||||
|
|
@ -272,14 +275,22 @@ func TestTransactionPriceNonceSort1559(t *testing.T) {
|
|||
// Tests that transactions can be correctly sorted according to their price in
|
||||
// decreasing order, but at the same time with increasing nonces when issued by
|
||||
// the same account.
|
||||
func testTransactionPriceNonceSort(t *testing.T, baseFee *big.Int) {
|
||||
//
|
||||
//nolint:gocognit,thelper
|
||||
func testTransactionPriceNonceSort(t *testing.T, baseFeeBig *big.Int) {
|
||||
// Generate a batch of accounts to start with
|
||||
keys := make([]*ecdsa.PrivateKey, 25)
|
||||
for i := 0; i < len(keys); i++ {
|
||||
keys[i], _ = crypto.GenerateKey()
|
||||
}
|
||||
|
||||
signer := LatestSignerForChainID(common.Big1)
|
||||
|
||||
var baseFee *uint256.Int
|
||||
if baseFeeBig != nil {
|
||||
baseFee = cmath.FromBig(baseFeeBig)
|
||||
}
|
||||
|
||||
// Generate a batch of transactions with overlapping values, but shifted nonces
|
||||
groups := map[common.Address]Transactions{}
|
||||
expectedCount := 0
|
||||
|
|
@ -308,7 +319,7 @@ func testTransactionPriceNonceSort(t *testing.T, baseFee *big.Int) {
|
|||
GasTipCap: big.NewInt(int64(rand.Intn(gasFeeCap + 1))),
|
||||
Data: nil,
|
||||
})
|
||||
if count == 25 && int64(gasFeeCap) < baseFee.Int64() {
|
||||
if count == 25 && uint64(gasFeeCap) < baseFee.Uint64() {
|
||||
count = i
|
||||
}
|
||||
}
|
||||
|
|
@ -341,12 +352,25 @@ func testTransactionPriceNonceSort(t *testing.T, baseFee *big.Int) {
|
|||
t.Errorf("invalid nonce ordering: tx #%d (A=%x N=%v) < tx #%d (A=%x N=%v)", i, fromi[:4], txi.Nonce(), i+j, fromj[:4], txj.Nonce())
|
||||
}
|
||||
}
|
||||
|
||||
// If the next tx has different from account, the price must be lower than the current one
|
||||
if i+1 < len(txs) {
|
||||
next := txs[i+1]
|
||||
fromNext, _ := Sender(signer, next)
|
||||
tip, err := txi.EffectiveGasTip(baseFee)
|
||||
nextTip, nextErr := next.EffectiveGasTip(baseFee)
|
||||
tip, err := txi.EffectiveGasTipUnit(baseFee)
|
||||
nextTip, nextErr := next.EffectiveGasTipUnit(baseFee)
|
||||
|
||||
tipBig, _ := txi.EffectiveGasTip(baseFeeBig)
|
||||
nextTipBig, _ := next.EffectiveGasTip(baseFeeBig)
|
||||
|
||||
if tip.Cmp(cmath.FromBig(tipBig)) != 0 {
|
||||
t.Fatalf("EffectiveGasTip incorrect. uint256 %q, big.Int %q, baseFee %q, baseFeeBig %q", tip.String(), tipBig.String(), baseFee.String(), baseFeeBig.String())
|
||||
}
|
||||
|
||||
if nextTip.Cmp(cmath.FromBig(nextTipBig)) != 0 {
|
||||
t.Fatalf("EffectiveGasTip next incorrect. uint256 %q, big.Int %q, baseFee %q, baseFeeBig %q", nextTip.String(), nextTipBig.String(), baseFee.String(), baseFeeBig.String())
|
||||
}
|
||||
|
||||
if err != nil || nextErr != nil {
|
||||
t.Errorf("error calculating effective tip")
|
||||
}
|
||||
|
|
|
|||
|
|
@ -30,7 +30,7 @@ import (
|
|||
"github.com/ethereum/go-ethereum/crypto/bn256"
|
||||
"github.com/ethereum/go-ethereum/params"
|
||||
|
||||
//lint:ignore SA1019 Needed for precompile
|
||||
big2 "github.com/holiman/big"
|
||||
"golang.org/x/crypto/ripemd160"
|
||||
)
|
||||
|
||||
|
|
@ -266,6 +266,7 @@ var (
|
|||
// modexpMultComplexity implements bigModexp multComplexity formula, as defined in EIP-198
|
||||
//
|
||||
// def mult_complexity(x):
|
||||
//
|
||||
// if x <= 64: return x ** 2
|
||||
// elif x <= 1024: return x ** 2 // 4 + 96 * x - 3072
|
||||
// else: return x ** 2 // 16 + 480 * x - 199680
|
||||
|
|
@ -379,15 +380,24 @@ func (c *bigModExp) Run(input []byte) ([]byte, error) {
|
|||
}
|
||||
// Retrieve the operands and execute the exponentiation
|
||||
var (
|
||||
base = new(big.Int).SetBytes(getData(input, 0, baseLen))
|
||||
exp = new(big.Int).SetBytes(getData(input, baseLen, expLen))
|
||||
mod = new(big.Int).SetBytes(getData(input, baseLen+expLen, modLen))
|
||||
base = new(big2.Int).SetBytes(getData(input, 0, baseLen))
|
||||
exp = new(big2.Int).SetBytes(getData(input, baseLen, expLen))
|
||||
mod = new(big2.Int).SetBytes(getData(input, baseLen+expLen, modLen))
|
||||
v []byte
|
||||
)
|
||||
if mod.BitLen() == 0 {
|
||||
|
||||
switch {
|
||||
case mod.BitLen() == 0:
|
||||
// Modulo 0 is undefined, return zero
|
||||
return common.LeftPadBytes([]byte{}, int(modLen)), nil
|
||||
case base.BitLen() == 1: // a bit length of 1 means it's 1 (or -1).
|
||||
//If base == 1, then we can just return base % mod (if mod >= 1, which it is)
|
||||
v = base.Mod(base, mod).Bytes()
|
||||
default:
|
||||
v = base.Exp(base, exp, mod).Bytes()
|
||||
}
|
||||
return common.LeftPadBytes(base.Exp(base, exp, mod).Bytes(), int(modLen)), nil
|
||||
|
||||
return common.LeftPadBytes(v, int(modLen)), nil
|
||||
}
|
||||
|
||||
// newCurvePoint unmarshals a binary blob into a bn256 elliptic curve point,
|
||||
|
|
|
|||
|
|
@ -93,7 +93,7 @@ ethstats = "" # Reporting URL of a ethstats service (nodename:sec
|
|||
vhosts = ["localhost"] # Comma separated list of virtual hostnames from which to accept requests (server enforced). Accepts '*' wildcard.
|
||||
corsdomain = ["localhost"] # Comma separated list of domains from which to accept cross origin requests (browser enforced)
|
||||
[jsonrpc.timeouts]
|
||||
read = "30s"
|
||||
read = "10s"
|
||||
write = "30s"
|
||||
idle = "2m0s"
|
||||
|
||||
|
|
|
|||
|
|
@ -236,11 +236,18 @@ func (b *EthAPIBackend) SubscribeLogsEvent(ch chan<- []*types.Log) event.Subscri
|
|||
}
|
||||
|
||||
func (b *EthAPIBackend) SendTx(ctx context.Context, signedTx *types.Transaction) error {
|
||||
return b.eth.txPool.AddLocal(signedTx)
|
||||
err := b.eth.txPool.AddLocal(signedTx)
|
||||
if err != nil {
|
||||
if unwrapped := errors.Unwrap(err); unwrapped != nil {
|
||||
return unwrapped
|
||||
}
|
||||
}
|
||||
|
||||
return err
|
||||
}
|
||||
|
||||
func (b *EthAPIBackend) GetPoolTransactions() (types.Transactions, error) {
|
||||
pending := b.eth.txPool.Pending(false)
|
||||
pending := b.eth.txPool.Pending(context.Background(), false)
|
||||
var txs types.Transactions
|
||||
for _, batch := range pending {
|
||||
txs = append(txs, batch...)
|
||||
|
|
|
|||
|
|
@ -26,6 +26,7 @@ func newCheckpointVerifier(verifyFn func(ctx context.Context, handler *ethHandle
|
|||
)
|
||||
|
||||
// check if we have the checkpoint blocks
|
||||
//nolint:contextcheck
|
||||
head := handler.ethAPI.BlockNumber()
|
||||
if head < hexutil.Uint64(endBlock) {
|
||||
log.Debug("Head block behind checkpoint block", "head", head, "checkpoint end block", endBlock)
|
||||
|
|
|
|||
|
|
@ -17,6 +17,7 @@
|
|||
package eth
|
||||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"math"
|
||||
"math/big"
|
||||
|
|
@ -69,7 +70,7 @@ type txPool interface {
|
|||
|
||||
// Pending should return pending transactions.
|
||||
// The slice should be modifiable by the caller.
|
||||
Pending(enforceTips bool) map[common.Address]types.Transactions
|
||||
Pending(ctx context.Context, enforceTips bool) map[common.Address]types.Transactions
|
||||
|
||||
// SubscribeNewTxsEvent should return an event subscription of
|
||||
// NewTxsEvent and send events to the given channel.
|
||||
|
|
|
|||
|
|
@ -17,6 +17,7 @@
|
|||
package eth
|
||||
|
||||
import (
|
||||
"context"
|
||||
"math/big"
|
||||
"sort"
|
||||
"sync"
|
||||
|
|
@ -92,7 +93,7 @@ func (p *testTxPool) AddRemotes(txs []*types.Transaction) []error {
|
|||
}
|
||||
|
||||
// Pending returns all the transactions known to the pool
|
||||
func (p *testTxPool) Pending(enforceTips bool) map[common.Address]types.Transactions {
|
||||
func (p *testTxPool) Pending(ctx context.Context, enforceTips bool) map[common.Address]types.Transactions {
|
||||
p.lock.RLock()
|
||||
defer p.lock.RUnlock()
|
||||
|
||||
|
|
|
|||
|
|
@ -17,6 +17,7 @@
|
|||
package eth
|
||||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"math/big"
|
||||
"sync/atomic"
|
||||
|
|
@ -44,20 +45,24 @@ func (h *handler) syncTransactions(p *eth.Peer) {
|
|||
//
|
||||
// TODO(karalabe): Figure out if we could get away with random order somehow
|
||||
var txs types.Transactions
|
||||
pending := h.txpool.Pending(false)
|
||||
|
||||
pending := h.txpool.Pending(context.Background(), false)
|
||||
for _, batch := range pending {
|
||||
txs = append(txs, batch...)
|
||||
}
|
||||
|
||||
if len(txs) == 0 {
|
||||
return
|
||||
}
|
||||
// The eth/65 protocol introduces proper transaction announcements, so instead
|
||||
// of dripping transactions across multiple peers, just send the entire list as
|
||||
// an announcement and let the remote side decide what they need (likely nothing).
|
||||
|
||||
hashes := make([]common.Hash, len(txs))
|
||||
for i, tx := range txs {
|
||||
hashes[i] = tx.Hash()
|
||||
}
|
||||
|
||||
p.AsyncSendPooledTransactionHashes(hashes)
|
||||
}
|
||||
|
||||
|
|
|
|||
23
go.mod
23
go.mod
|
|
@ -12,13 +12,13 @@ require (
|
|||
github.com/aws/aws-sdk-go-v2/config v1.1.1
|
||||
github.com/aws/aws-sdk-go-v2/credentials v1.1.1
|
||||
github.com/aws/aws-sdk-go-v2/service/route53 v1.1.1
|
||||
github.com/btcsuite/btcd/btcec/v2 v2.1.2
|
||||
github.com/btcsuite/btcd/btcec/v2 v2.1.3
|
||||
github.com/cespare/cp v0.1.0
|
||||
github.com/cloudflare/cloudflare-go v0.14.0
|
||||
github.com/consensys/gnark-crypto v0.4.1-0.20210426202927-39ac3d4b3f1f
|
||||
github.com/davecgh/go-spew v1.1.1
|
||||
github.com/deckarep/golang-set v1.8.0
|
||||
github.com/docker/docker v1.4.2-0.20180625184442-8e610b2b55bf
|
||||
github.com/docker/docker v1.6.1
|
||||
github.com/dop251/goja v0.0.0-20211011172007-d99e4b8cbf48
|
||||
github.com/edsrzf/mmap-go v1.0.0
|
||||
github.com/fatih/color v1.7.0
|
||||
|
|
@ -37,6 +37,7 @@ require (
|
|||
github.com/hashicorp/go-bexpr v0.1.10
|
||||
github.com/hashicorp/golang-lru v0.5.5-0.20210104140557-80c98217689d
|
||||
github.com/hashicorp/hcl/v2 v2.10.1
|
||||
github.com/holiman/big v0.0.0-20221017200358-a027dc42d04e
|
||||
github.com/holiman/bloomfilter/v2 v2.0.3
|
||||
github.com/holiman/uint256 v1.2.0
|
||||
github.com/huin/goupnp v1.0.3-0.20220313090229-ca81a64b4204
|
||||
|
|
@ -69,12 +70,12 @@ require (
|
|||
go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.2.0
|
||||
go.opentelemetry.io/otel/sdk v1.2.0
|
||||
go.uber.org/goleak v1.1.12
|
||||
golang.org/x/crypto v0.0.0-20220507011949-2cf3adece122
|
||||
golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4
|
||||
golang.org/x/sys v0.0.0-20220728004956-3c1f35247d10
|
||||
golang.org/x/text v0.3.7
|
||||
golang.org/x/crypto v0.1.0
|
||||
golang.org/x/sync v0.1.0
|
||||
golang.org/x/sys v0.6.0
|
||||
golang.org/x/text v0.8.0
|
||||
golang.org/x/time v0.0.0-20210220033141-f8bda1e9f3ba
|
||||
golang.org/x/tools v0.1.12
|
||||
golang.org/x/tools v0.6.0
|
||||
gonum.org/v1/gonum v0.11.0
|
||||
google.golang.org/grpc v1.48.0
|
||||
google.golang.org/protobuf v1.28.0
|
||||
|
|
@ -90,7 +91,7 @@ require github.com/gammazero/deque v0.2.1 // indirect
|
|||
require (
|
||||
github.com/Azure/azure-sdk-for-go/sdk/azcore v0.21.1 // indirect
|
||||
github.com/Azure/azure-sdk-for-go/sdk/internal v0.8.3 // indirect
|
||||
github.com/Masterminds/goutils v1.1.0 // indirect
|
||||
github.com/Masterminds/goutils v1.1.1 // indirect
|
||||
github.com/Masterminds/semver v1.5.0 // indirect
|
||||
github.com/Masterminds/sprig v2.22.0+incompatible // indirect
|
||||
github.com/StackExchange/wmi v0.0.0-20180116203802-5d049714c4a6 // indirect
|
||||
|
|
@ -136,9 +137,9 @@ require (
|
|||
go.opentelemetry.io/otel/trace v1.2.0
|
||||
go.opentelemetry.io/proto/otlp v0.10.0 // indirect
|
||||
golang.org/x/exp v0.0.0-20220722155223-a9213eeb770e // indirect
|
||||
golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4 // indirect
|
||||
golang.org/x/net v0.0.0-20220728030405-41545e8bf201 // indirect
|
||||
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211 // indirect
|
||||
golang.org/x/mod v0.8.0 // indirect
|
||||
golang.org/x/net v0.8.0 // indirect
|
||||
golang.org/x/term v0.6.0 // indirect
|
||||
golang.org/x/xerrors v0.0.0-20220411194840-2f41105eb62f // indirect
|
||||
google.golang.org/genproto v0.0.0-20220725144611-272f38e5d71b // indirect
|
||||
gopkg.in/yaml.v2 v2.4.0 // indirect
|
||||
|
|
|
|||
44
go.sum
44
go.sum
|
|
@ -33,8 +33,9 @@ github.com/JekaMas/go-grpc-net-conn v0.0.0-20220708155319-6aff21f2d13d h1:RO27lg
|
|||
github.com/JekaMas/go-grpc-net-conn v0.0.0-20220708155319-6aff21f2d13d/go.mod h1:romz7UPgSYhfJkKOalzEEyV6sWtt/eAEm0nX2aOrod0=
|
||||
github.com/JekaMas/workerpool v1.1.5 h1:xmrx2Zyft95CEGiEqzDxiawptCIRZQ0zZDhTGDFOCaw=
|
||||
github.com/JekaMas/workerpool v1.1.5/go.mod h1:IoDWPpwMcA27qbuugZKeBslDrgX09lVmksuh9sjzbhc=
|
||||
github.com/Masterminds/goutils v1.1.0 h1:zukEsf/1JZwCMgHiK3GZftabmxiCw4apj3a28RPBiVg=
|
||||
github.com/Masterminds/goutils v1.1.0/go.mod h1:8cTjp+g8YejhMuvIA5y2vz3BpJxksy863GQaJW2MFNU=
|
||||
github.com/Masterminds/goutils v1.1.1 h1:5nUrii3FMTL5diU80unEVvNevw1nH4+ZV4DSLVJLSYI=
|
||||
github.com/Masterminds/goutils v1.1.1/go.mod h1:8cTjp+g8YejhMuvIA5y2vz3BpJxksy863GQaJW2MFNU=
|
||||
github.com/Masterminds/semver v1.5.0 h1:H65muMkzWKEuNDnfl9d70GUjFniHKHRbFPGBuZ3QEww=
|
||||
github.com/Masterminds/semver v1.5.0/go.mod h1:MB6lktGJrhw8PrUyiEoblNEGEQ+RzHPF078ddwwvV3Y=
|
||||
github.com/Masterminds/sprig v2.22.0+incompatible h1:z4yfnGrZ7netVz+0EDJ0Wi+5VZCSYp4Z0m2dk6cEM60=
|
||||
|
|
@ -84,8 +85,8 @@ github.com/bgentry/speakeasy v0.1.0 h1:ByYyxL9InA1OWqxJqqp2A5pYHUrCiAL6K3J+LKSsQ
|
|||
github.com/bgentry/speakeasy v0.1.0/go.mod h1:+zsyZBPWlz7T6j88CTgSN5bM796AkVf0kBD4zp0CCIs=
|
||||
github.com/bmizerany/pat v0.0.0-20170815010413-6226ea591a40/go.mod h1:8rLXio+WjiTceGBHIoTvn60HIbs7Hm7bcHjyrSqYB9c=
|
||||
github.com/boltdb/bolt v1.3.1/go.mod h1:clJnj/oiGkjum5o1McbSZDSLxVThjynRyGBgiAx27Ps=
|
||||
github.com/btcsuite/btcd/btcec/v2 v2.1.2 h1:YoYoC9J0jwfukodSBMzZYUVQ8PTiYg4BnOWiJVzTmLs=
|
||||
github.com/btcsuite/btcd/btcec/v2 v2.1.2/go.mod h1:ctjw4H1kknNJmRN4iP1R7bTQ+v3GJkZBd6mui8ZsAZE=
|
||||
github.com/btcsuite/btcd/btcec/v2 v2.1.3 h1:xM/n3yIhHAhHy04z4i43C8p4ehixJZMsnrVJkgl+MTE=
|
||||
github.com/btcsuite/btcd/btcec/v2 v2.1.3/go.mod h1:ctjw4H1kknNJmRN4iP1R7bTQ+v3GJkZBd6mui8ZsAZE=
|
||||
github.com/btcsuite/btcd/chaincfg/chainhash v1.0.0 h1:MSskdM4/xJYcFzy0altH/C/xHopifpWzHUi1JeVI34Q=
|
||||
github.com/c-bata/go-prompt v0.2.2/go.mod h1:VzqtzE2ksDBcdln8G7mk2RX9QyGjH+OVqOCSiVIqS34=
|
||||
github.com/cenkalti/backoff/v4 v4.1.1 h1:G2HAfAmvm/GcKan2oOQpBXOd2tT2G57ZnZGWa1PxPBQ=
|
||||
|
|
@ -136,8 +137,8 @@ github.com/dlclark/regexp2 v1.4.1-0.20201116162257-a2a8dda75c91/go.mod h1:2pZnwu
|
|||
github.com/dnaeon/go-vcr v1.1.0/go.mod h1:M7tiix8f0r6mKKJ3Yq/kqU1OYf3MnfmBWVbPx/yU9ko=
|
||||
github.com/dnaeon/go-vcr v1.2.0 h1:zHCHvJYTMh1N7xnV7zf1m1GPBF9Ad0Jk/whtQ1663qI=
|
||||
github.com/dnaeon/go-vcr v1.2.0/go.mod h1:R4UdLID7HZT3taECzJs4YgbbH6PIGXB6W/sc5OLb6RQ=
|
||||
github.com/docker/docker v1.4.2-0.20180625184442-8e610b2b55bf h1:sh8rkQZavChcmakYiSlqu2425CHyFXLZZnvm7PDpU8M=
|
||||
github.com/docker/docker v1.4.2-0.20180625184442-8e610b2b55bf/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk=
|
||||
github.com/docker/docker v1.6.1 h1:4xYASHy5cScPkLD7PO0uTmnVc860m9NarPN1X8zeMe8=
|
||||
github.com/docker/docker v1.6.1/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk=
|
||||
github.com/dop251/goja v0.0.0-20211011172007-d99e4b8cbf48 h1:iZOop7pqsg+56twTopWgwCGxdB5SI2yDO8Ti7eTRliQ=
|
||||
github.com/dop251/goja v0.0.0-20211011172007-d99e4b8cbf48/go.mod h1:R9ET47fwRVRPZnOGvHxxhuZcbrMCuiqOz3Rlrh4KSnk=
|
||||
github.com/dop251/goja_nodejs v0.0.0-20210225215109-d91c329300e7/go.mod h1:hn7BA7c8pLvoGndExHudxTDKZ84Pyvv+90pbBjbTz0Y=
|
||||
|
|
@ -275,6 +276,8 @@ github.com/hashicorp/golang-lru v0.5.5-0.20210104140557-80c98217689d h1:dg1dEPuW
|
|||
github.com/hashicorp/golang-lru v0.5.5-0.20210104140557-80c98217689d/go.mod h1:iADmTwqILo4mZ8BN3D2Q6+9jd8WM5uGBxy+E8yxSoD4=
|
||||
github.com/hashicorp/hcl/v2 v2.10.1 h1:h4Xx4fsrRE26ohAk/1iGF/JBqRQbyUqu5Lvj60U54ys=
|
||||
github.com/hashicorp/hcl/v2 v2.10.1/go.mod h1:FwWsfWEjyV/CMj8s/gqAuiviY72rJ1/oayI9WftqcKg=
|
||||
github.com/holiman/big v0.0.0-20221017200358-a027dc42d04e h1:pIYdhNkDh+YENVNi3gto8n9hAmRxKxoar0iE6BLucjw=
|
||||
github.com/holiman/big v0.0.0-20221017200358-a027dc42d04e/go.mod h1:j9cQbcqHQujT0oKJ38PylVfqohClLr3CvDC+Qcg+lhU=
|
||||
github.com/holiman/bloomfilter/v2 v2.0.3 h1:73e0e/V0tCydx14a0SCYS/EWCxgwLZ18CZcZKVu0fao=
|
||||
github.com/holiman/bloomfilter/v2 v2.0.3/go.mod h1:zpoh+gs7qcpqrHr3dB55AMiJwo0iURXE7ZOP9L9hSkA=
|
||||
github.com/holiman/uint256 v1.2.0 h1:gpSYcPLWGv4sG43I2mVLiDZCNDh/EpGjSk8tmtxitHM=
|
||||
|
|
@ -535,8 +538,8 @@ golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPh
|
|||
golang.org/x/crypto v0.0.0-20200820211705-5c72a883971a/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
|
||||
golang.org/x/crypto v0.0.0-20201221181555-eec23a3978ad/go.mod h1:jdWPYTVW3xRLrWPugEBEK3UY2ZEsg3UU495nc5E+M+I=
|
||||
golang.org/x/crypto v0.0.0-20210322153248-0c34fe9e7dc2/go.mod h1:T9bdIzuCu7OtxOm1hfPfRQxPLYneinmdGuTeoZ9dtd4=
|
||||
golang.org/x/crypto v0.0.0-20220507011949-2cf3adece122 h1:NvGWuYG8dkDHFSKksI1P9faiVJ9rayE6l0+ouWVIDs8=
|
||||
golang.org/x/crypto v0.0.0-20220507011949-2cf3adece122/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4=
|
||||
golang.org/x/crypto v0.1.0 h1:MDRAIl0xIo9Io2xV565hzXHw3zVseKrJKodhohM5CjU=
|
||||
golang.org/x/crypto v0.1.0/go.mod h1:RecgLatLF4+eUMCP1PoPZQb+cVrJcOPbHkTkbkB9sbw=
|
||||
golang.org/x/exp v0.0.0-20180321215751-8460e604b9de/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
|
||||
golang.org/x/exp v0.0.0-20180807140117-3d87b88a115f/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
|
||||
golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
|
||||
|
|
@ -569,8 +572,8 @@ golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee/go.mod h1:QqPTAvyqsEbceGzB
|
|||
golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
|
||||
golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
|
||||
golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
|
||||
golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4 h1:6zppjxzCulZykYSLyVDYbneBfbaBIQPYMevg0bEwv2s=
|
||||
golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4=
|
||||
golang.org/x/mod v0.8.0 h1:LUYupSeNrTNCGzR/hVBk2NHZO4hXcVaW1k4Qx7rjPx8=
|
||||
golang.org/x/mod v0.8.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs=
|
||||
golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
golang.org/x/net v0.0.0-20180811021610-c39426892332/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
|
|
@ -600,8 +603,8 @@ golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v
|
|||
golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM=
|
||||
golang.org/x/net v0.0.0-20210610132358-84b48f89b13b/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
|
||||
golang.org/x/net v0.0.0-20210805182204-aaa1db679c0d/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
|
||||
golang.org/x/net v0.0.0-20220728030405-41545e8bf201 h1:bvOltf3SADAfG05iRml8lAB3qjoEX5RCyN4K6G5v3N0=
|
||||
golang.org/x/net v0.0.0-20220728030405-41545e8bf201/go.mod h1:YDH+HFinaLZZlnHAfSS6ZXJJ9M9t4Dl22yv3iI2vPwk=
|
||||
golang.org/x/net v0.8.0 h1:Zrh2ngAOFYneWTAIAPethzeaQLuHwhuBkuV6ZiRnUaQ=
|
||||
golang.org/x/net v0.8.0/go.mod h1:QVkue5JL9kW//ek3r6jTKnTFis1tRmNAW2P1shuFdJc=
|
||||
golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
|
||||
golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
|
||||
golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
|
||||
|
|
@ -615,8 +618,8 @@ golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJ
|
|||
golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4 h1:uVc8UZUe6tr40fFVnUP5Oj+veunVezqYl9z7DYw9xzw=
|
||||
golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.1.0 h1:wsuoTGHzEhffawBOhz5CYhcrV4IdKZbEyZjBMuTp12o=
|
||||
golang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
|
|
@ -658,12 +661,12 @@ golang.org/x/sys v0.0.0-20210420205809-ac73e9fd8988/go.mod h1:h1NjWce9XRLGQEsW7w
|
|||
golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20210423185535-09eb48e85fd7/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20210510120138-977fb7262007/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20220728004956-3c1f35247d10 h1:WIoqL4EROvwiPdUtaip4VcDdpZ4kha7wBWZrbVKCIZg=
|
||||
golang.org/x/sys v0.0.0-20220728004956-3c1f35247d10/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.6.0 h1:MVltZSvRTcU2ljQOhs94SXPftV6DCNnZViHeQps87pQ=
|
||||
golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/term v0.0.0-20201117132131-f5c789dd3221/go.mod h1:Nr5EML6q2oocZ2LXRh80K7BxOlk5/8JxuGnuhpl+muw=
|
||||
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
|
||||
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211 h1:JGgROgKl9N8DuW20oFS5gxc+lE67/N3FcwmBPMe7ArY=
|
||||
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
|
||||
golang.org/x/term v0.6.0 h1:clScbb1cHjoCkyRbWwBEUZ5H/tIFu5TAXIqaZD0Gcjw=
|
||||
golang.org/x/term v0.6.0/go.mod h1:m6U89DPEgQRMq3DNkDClhWw02AUbt2daBVO4cn4Hv9U=
|
||||
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||
golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||
golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk=
|
||||
|
|
@ -671,8 +674,9 @@ golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
|||
golang.org/x/text v0.3.4/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
||||
golang.org/x/text v0.3.5/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
||||
golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
||||
golang.org/x/text v0.3.7 h1:olpwvP2KacW1ZWvsR7uQhoyTYvKAupfQrRGBFM352Gk=
|
||||
golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ=
|
||||
golang.org/x/text v0.8.0 h1:57P1ETyNKtuIjB4SRd15iJxuhj8Gc416Y78H3qgMh68=
|
||||
golang.org/x/text v0.8.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8=
|
||||
golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
|
||||
golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
|
||||
golang.org/x/time v0.0.0-20201208040808-7e3f01d25324/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
|
||||
|
|
@ -709,8 +713,8 @@ golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4f
|
|||
golang.org/x/tools v0.1.0/go.mod h1:xkSsbof2nBLbhDlRMhhhyNLN/zl3eTqcnHD5viDpcZ0=
|
||||
golang.org/x/tools v0.1.1/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk=
|
||||
golang.org/x/tools v0.1.5/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk=
|
||||
golang.org/x/tools v0.1.12 h1:VveCTK38A2rkS8ZqFY25HIDFscX5X9OoEhJd3quQmXU=
|
||||
golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc=
|
||||
golang.org/x/tools v0.6.0 h1:BOw41kyTf3PuCW1pVQf8+Cyg8pMlkYB1oo9iJ6D/lKM=
|
||||
golang.org/x/tools v0.6.0/go.mod h1:Xwgl3UAJ/d3gWutnCtw505GrjyAbvKui8lOU390QaIU=
|
||||
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
|
|
|
|||
|
|
@ -540,7 +540,7 @@ func DefaultConfig() *Config {
|
|||
VHost: []string{"localhost"},
|
||||
},
|
||||
HttpTimeout: &HttpTimeouts{
|
||||
ReadTimeout: 30 * time.Second,
|
||||
ReadTimeout: 10 * time.Second,
|
||||
WriteTimeout: 30 * time.Second,
|
||||
IdleTimeout: 120 * time.Second,
|
||||
},
|
||||
|
|
|
|||
|
|
@ -61,6 +61,28 @@ func CPUProfile(ctx context.Context, sec int) ([]byte, map[string]string, error)
|
|||
}, nil
|
||||
}
|
||||
|
||||
// CPUProfile generates a CPU Profile for a given duration
|
||||
func CPUProfileWithChannel(done chan bool) ([]byte, map[string]string, error) {
|
||||
var buf bytes.Buffer
|
||||
if err := pprof.StartCPUProfile(&buf); err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
|
||||
select {
|
||||
case <-done:
|
||||
case <-time.After(30 * time.Second):
|
||||
}
|
||||
|
||||
pprof.StopCPUProfile()
|
||||
|
||||
return buf.Bytes(),
|
||||
map[string]string{
|
||||
"X-Content-Type-Options": "nosniff",
|
||||
"Content-Type": "application/octet-stream",
|
||||
"Content-Disposition": `attachment; filename="profile"`,
|
||||
}, nil
|
||||
}
|
||||
|
||||
// Trace runs a trace profile for a given duration
|
||||
func Trace(ctx context.Context, sec int) ([]byte, map[string]string, error) {
|
||||
if sec <= 0 {
|
||||
|
|
|
|||
|
|
@ -21,6 +21,7 @@ import (
|
|||
"errors"
|
||||
"fmt"
|
||||
"math/big"
|
||||
"runtime"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
|
|
@ -1457,7 +1458,15 @@ func newRPCPendingTransaction(tx *types.Transaction, current *types.Header, conf
|
|||
func newRPCTransactionFromBlockIndex(b *types.Block, index uint64, config *params.ChainConfig, db ethdb.Database) *RPCTransaction {
|
||||
txs := b.Transactions()
|
||||
|
||||
borReceipt := rawdb.ReadBorReceipt(db, b.Hash(), b.NumberU64(), config)
|
||||
if index >= uint64(len(txs)+1) {
|
||||
return nil
|
||||
}
|
||||
|
||||
var borReceipt *types.Receipt
|
||||
|
||||
// Read bor receipts if a state-sync transaction is requested
|
||||
if index == uint64(len(txs)) {
|
||||
borReceipt = rawdb.ReadBorReceipt(db, b.Hash(), b.NumberU64(), config)
|
||||
if borReceipt != nil {
|
||||
if borReceipt.TxHash != (common.Hash{}) {
|
||||
borTx, _, _, _ := rawdb.ReadBorTransactionWithBlockHash(db, borReceipt.TxHash, b.Hash())
|
||||
|
|
@ -1466,7 +1475,9 @@ func newRPCTransactionFromBlockIndex(b *types.Block, index uint64, config *param
|
|||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// If the index is still out of the range after checking bor state sync transaction, it means that the transaction index is invalid
|
||||
if index >= uint64(len(txs)) {
|
||||
return nil
|
||||
}
|
||||
|
|
@ -1474,7 +1485,7 @@ func newRPCTransactionFromBlockIndex(b *types.Block, index uint64, config *param
|
|||
rpcTx := newRPCTransaction(txs[index], b.Hash(), b.NumberU64(), index, b.BaseFee(), config)
|
||||
|
||||
// If the transaction is a bor transaction, we need to set the hash to the derived bor tx hash. BorTx is always the last index.
|
||||
if borReceipt != nil && int(index) == len(txs)-1 {
|
||||
if borReceipt != nil && index == uint64(len(txs)-1) {
|
||||
rpcTx.Hash = borReceipt.TxHash
|
||||
}
|
||||
|
||||
|
|
@ -2222,6 +2233,21 @@ func (api *PrivateDebugAPI) PurgeCheckpointWhitelist() {
|
|||
api.b.PurgeCheckpointWhitelist()
|
||||
}
|
||||
|
||||
// GetTraceStack returns the current trace stack
|
||||
func (api *PrivateDebugAPI) GetTraceStack() string {
|
||||
buf := make([]byte, 1024)
|
||||
|
||||
for {
|
||||
n := runtime.Stack(buf, true)
|
||||
|
||||
if n < len(buf) {
|
||||
return string(buf)
|
||||
}
|
||||
|
||||
buf = make([]byte, 2*len(buf))
|
||||
}
|
||||
}
|
||||
|
||||
// PublicNetAPI offers network related RPC methods
|
||||
type PublicNetAPI struct {
|
||||
net *p2p.Server
|
||||
|
|
|
|||
|
|
@ -148,3 +148,35 @@ func (l *logger) flush() {
|
|||
}
|
||||
l.h.buf = nil
|
||||
}
|
||||
|
||||
func (l *logger) OnTrace(fn func(l log.Logging)) {
|
||||
if l.GetHandler().Level() >= log.LvlTrace {
|
||||
fn(l.Trace)
|
||||
}
|
||||
}
|
||||
|
||||
func (l *logger) OnDebug(fn func(l log.Logging)) {
|
||||
if l.GetHandler().Level() >= log.LvlDebug {
|
||||
fn(l.Debug)
|
||||
}
|
||||
}
|
||||
func (l *logger) OnInfo(fn func(l log.Logging)) {
|
||||
if l.GetHandler().Level() >= log.LvlInfo {
|
||||
fn(l.Info)
|
||||
}
|
||||
}
|
||||
func (l *logger) OnWarn(fn func(l log.Logging)) {
|
||||
if l.GetHandler().Level() >= log.LvlWarn {
|
||||
fn(l.Warn)
|
||||
}
|
||||
}
|
||||
func (l *logger) OnError(fn func(l log.Logging)) {
|
||||
if l.GetHandler().Level() >= log.LvlError {
|
||||
fn(l.Error)
|
||||
}
|
||||
}
|
||||
func (l *logger) OnCrit(fn func(l log.Logging)) {
|
||||
if l.GetHandler().Level() >= log.LvlCrit {
|
||||
fn(l.Crit)
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -512,6 +512,11 @@ web3._extend({
|
|||
call: 'debug_purgeCheckpointWhitelist',
|
||||
params: 0,
|
||||
}),
|
||||
new web3._extend.Method({
|
||||
name: 'getTraceStack',
|
||||
call: 'debug_getTraceStack',
|
||||
params: 0,
|
||||
}),
|
||||
],
|
||||
properties: []
|
||||
});
|
||||
|
|
|
|||
|
|
@ -617,7 +617,7 @@ func testTransactionStatus(t *testing.T, protocol int) {
|
|||
sendRequest(rawPeer.app, GetTxStatusMsg, reqID, []common.Hash{tx.Hash()})
|
||||
}
|
||||
if err := expectResponse(rawPeer.app, TxStatusMsg, reqID, testBufLimit, []light.TxStatus{expStatus}); err != nil {
|
||||
t.Errorf("transaction status mismatch")
|
||||
t.Error("transaction status mismatch", err)
|
||||
}
|
||||
}
|
||||
signer := types.HomesteadSigner{}
|
||||
|
|
|
|||
|
|
@ -507,25 +507,39 @@ func handleSendTx(msg Decoder) (serveRequestFn, uint64, uint64, error) {
|
|||
if err := msg.Decode(&r); err != nil {
|
||||
return nil, 0, 0, err
|
||||
}
|
||||
|
||||
amount := uint64(len(r.Txs))
|
||||
|
||||
return func(backend serverBackend, p *clientPeer, waitOrStop func() bool) *reply {
|
||||
stats := make([]light.TxStatus, len(r.Txs))
|
||||
|
||||
var (
|
||||
err error
|
||||
addFn func(transaction *types.Transaction) error
|
||||
)
|
||||
|
||||
for i, tx := range r.Txs {
|
||||
if i != 0 && !waitOrStop() {
|
||||
return nil
|
||||
}
|
||||
|
||||
hash := tx.Hash()
|
||||
stats[i] = txStatus(backend, hash)
|
||||
|
||||
if stats[i].Status == core.TxStatusUnknown {
|
||||
addFn := backend.TxPool().AddRemotes
|
||||
addFn = backend.TxPool().AddRemote
|
||||
|
||||
// Add txs synchronously for testing purpose
|
||||
if backend.AddTxsSync() {
|
||||
addFn = backend.TxPool().AddRemotesSync
|
||||
addFn = backend.TxPool().AddRemoteSync
|
||||
}
|
||||
if errs := addFn([]*types.Transaction{tx}); errs[0] != nil {
|
||||
stats[i].Error = errs[0].Error()
|
||||
|
||||
if err = addFn(tx); err != nil {
|
||||
stats[i].Error = err.Error()
|
||||
|
||||
continue
|
||||
}
|
||||
|
||||
stats[i] = txStatus(backend, hash)
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -106,6 +106,8 @@ type RecordKeyNames struct {
|
|||
Ctx string
|
||||
}
|
||||
|
||||
type Logging func(msg string, ctx ...interface{})
|
||||
|
||||
// A Logger writes key/value pairs to a Handler
|
||||
type Logger interface {
|
||||
// New returns a new Logger that has this logger's context plus the given context
|
||||
|
|
@ -124,6 +126,13 @@ type Logger interface {
|
|||
Warn(msg string, ctx ...interface{})
|
||||
Error(msg string, ctx ...interface{})
|
||||
Crit(msg string, ctx ...interface{})
|
||||
|
||||
OnTrace(func(l Logging))
|
||||
OnDebug(func(l Logging))
|
||||
OnInfo(func(l Logging))
|
||||
OnWarn(func(l Logging))
|
||||
OnError(func(l Logging))
|
||||
OnCrit(func(l Logging))
|
||||
}
|
||||
|
||||
type logger struct {
|
||||
|
|
@ -198,6 +207,38 @@ func (l *logger) SetHandler(h Handler) {
|
|||
l.h.Swap(h)
|
||||
}
|
||||
|
||||
func (l *logger) OnTrace(fn func(l Logging)) {
|
||||
if l.GetHandler().Level() >= LvlTrace {
|
||||
fn(l.Trace)
|
||||
}
|
||||
}
|
||||
|
||||
func (l *logger) OnDebug(fn func(l Logging)) {
|
||||
if l.GetHandler().Level() >= LvlDebug {
|
||||
fn(l.Debug)
|
||||
}
|
||||
}
|
||||
func (l *logger) OnInfo(fn func(l Logging)) {
|
||||
if l.GetHandler().Level() >= LvlInfo {
|
||||
fn(l.Info)
|
||||
}
|
||||
}
|
||||
func (l *logger) OnWarn(fn func(l Logging)) {
|
||||
if l.GetHandler().Level() >= LvlWarn {
|
||||
fn(l.Warn)
|
||||
}
|
||||
}
|
||||
func (l *logger) OnError(fn func(l Logging)) {
|
||||
if l.GetHandler().Level() >= LvlError {
|
||||
fn(l.Error)
|
||||
}
|
||||
}
|
||||
func (l *logger) OnCrit(fn func(l Logging)) {
|
||||
if l.GetHandler().Level() >= LvlCrit {
|
||||
fn(l.Crit)
|
||||
}
|
||||
}
|
||||
|
||||
func normalize(ctx []interface{}) []interface{} {
|
||||
// if the caller passed a Ctx object, then expand it
|
||||
if len(ctx) == 1 {
|
||||
|
|
|
|||
32
log/root.go
32
log/root.go
|
|
@ -60,6 +60,38 @@ func Crit(msg string, ctx ...interface{}) {
|
|||
os.Exit(1)
|
||||
}
|
||||
|
||||
func OnTrace(fn func(l Logging)) {
|
||||
if root.GetHandler().Level() >= LvlTrace {
|
||||
fn(root.Trace)
|
||||
}
|
||||
}
|
||||
|
||||
func OnDebug(fn func(l Logging)) {
|
||||
if root.GetHandler().Level() >= LvlDebug {
|
||||
fn(root.Debug)
|
||||
}
|
||||
}
|
||||
func OnInfo(fn func(l Logging)) {
|
||||
if root.GetHandler().Level() >= LvlInfo {
|
||||
fn(root.Info)
|
||||
}
|
||||
}
|
||||
func OnWarn(fn func(l Logging)) {
|
||||
if root.GetHandler().Level() >= LvlWarn {
|
||||
fn(root.Warn)
|
||||
}
|
||||
}
|
||||
func OnError(fn func(l Logging)) {
|
||||
if root.GetHandler().Level() >= LvlError {
|
||||
fn(root.Error)
|
||||
}
|
||||
}
|
||||
func OnCrit(fn func(l Logging)) {
|
||||
if root.GetHandler().Level() >= LvlCrit {
|
||||
fn(root.Crit)
|
||||
}
|
||||
}
|
||||
|
||||
// Output is a convenient alias for write, allowing for the modification of
|
||||
// the calldepth (number of stack frames to skip).
|
||||
// calldepth influences the reported line number of the log message.
|
||||
|
|
|
|||
|
|
@ -47,7 +47,7 @@ func NewBorDefaultMiner(t *testing.T) *DefaultBorMiner {
|
|||
ethAPI.EXPECT().Call(gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any()).AnyTimes()
|
||||
|
||||
spanner := bor.NewMockSpanner(ctrl)
|
||||
spanner.EXPECT().GetCurrentValidators(gomock.Any(), gomock.Any(), gomock.Any()).Return([]*valset.Validator{
|
||||
spanner.EXPECT().GetCurrentValidatorsByHash(gomock.Any(), gomock.Any(), gomock.Any()).Return([]*valset.Validator{
|
||||
{
|
||||
ID: 0,
|
||||
Address: common.Address{0x1},
|
||||
|
|
|
|||
225
miner/worker.go
225
miner/worker.go
|
|
@ -17,10 +17,15 @@
|
|||
package miner
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"context"
|
||||
"errors"
|
||||
"fmt"
|
||||
"math/big"
|
||||
"os"
|
||||
"runtime"
|
||||
"runtime/pprof"
|
||||
ptrace "runtime/trace"
|
||||
"sync"
|
||||
"sync/atomic"
|
||||
"time"
|
||||
|
|
@ -31,14 +36,17 @@ import (
|
|||
"go.opentelemetry.io/otel/trace"
|
||||
|
||||
"github.com/ethereum/go-ethereum/common"
|
||||
cmath "github.com/ethereum/go-ethereum/common/math"
|
||||
"github.com/ethereum/go-ethereum/common/tracing"
|
||||
"github.com/ethereum/go-ethereum/consensus"
|
||||
"github.com/ethereum/go-ethereum/consensus/bor"
|
||||
"github.com/ethereum/go-ethereum/consensus/misc"
|
||||
"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/event"
|
||||
"github.com/ethereum/go-ethereum/log"
|
||||
"github.com/ethereum/go-ethereum/metrics"
|
||||
"github.com/ethereum/go-ethereum/params"
|
||||
"github.com/ethereum/go-ethereum/trie"
|
||||
)
|
||||
|
|
@ -83,6 +91,12 @@ const (
|
|||
staleThreshold = 7
|
||||
)
|
||||
|
||||
// metrics gauge to track total and empty blocks sealed by a miner
|
||||
var (
|
||||
sealedBlocksCounter = metrics.NewRegisteredCounter("worker/sealedBlocks", nil)
|
||||
sealedEmptyBlocksCounter = metrics.NewRegisteredCounter("worker/sealedEmptyBlocks", nil)
|
||||
)
|
||||
|
||||
// environment is the worker's current environment and holds all
|
||||
// information of the sealing block generation.
|
||||
type environment struct {
|
||||
|
|
@ -257,6 +271,8 @@ type worker struct {
|
|||
skipSealHook func(*task) bool // Method to decide whether skipping the sealing.
|
||||
fullTaskHook func() // Method to call before pushing the full sealing task.
|
||||
resubmitHook func(time.Duration, time.Duration) // Method to call upon updating resubmitting interval.
|
||||
|
||||
profileCount *int32 // Global count for profiling
|
||||
}
|
||||
|
||||
//nolint:staticcheck
|
||||
|
|
@ -285,6 +301,7 @@ func newWorker(config *Config, chainConfig *params.ChainConfig, engine consensus
|
|||
resubmitIntervalCh: make(chan time.Duration),
|
||||
resubmitAdjustCh: make(chan *intervalAdjust, resubmitAdjustChanSize),
|
||||
}
|
||||
worker.profileCount = new(int32)
|
||||
// Subscribe NewTxsEvent for tx pool
|
||||
worker.txsSub = eth.TxPool().SubscribeNewTxsEvent(worker.txsCh)
|
||||
// Subscribe events for blockchain
|
||||
|
|
@ -560,9 +577,11 @@ func (w *worker) mainLoop(ctx context.Context) {
|
|||
for {
|
||||
select {
|
||||
case req := <-w.newWorkCh:
|
||||
//nolint:contextcheck
|
||||
w.commitWork(req.ctx, req.interrupt, req.noempty, req.timestamp)
|
||||
|
||||
case req := <-w.getWorkCh:
|
||||
//nolint:contextcheck
|
||||
block, err := w.generateWork(req.ctx, req.params)
|
||||
if err != nil {
|
||||
req.err = err
|
||||
|
|
@ -622,13 +641,17 @@ func (w *worker) mainLoop(ctx context.Context) {
|
|||
if gp := w.current.gasPool; gp != nil && gp.Gas() < params.TxGas {
|
||||
continue
|
||||
}
|
||||
|
||||
txs := make(map[common.Address]types.Transactions)
|
||||
|
||||
for _, tx := range ev.Txs {
|
||||
acc, _ := types.Sender(w.current.signer, tx)
|
||||
txs[acc] = append(txs[acc], tx)
|
||||
}
|
||||
txset := types.NewTransactionsByPriceAndNonce(w.current.signer, txs, w.current.header.BaseFee)
|
||||
|
||||
txset := types.NewTransactionsByPriceAndNonce(w.current.signer, txs, cmath.FromBig(w.current.header.BaseFee))
|
||||
tcount := w.current.tcount
|
||||
|
||||
w.commitTransactions(w.current, txset, nil)
|
||||
|
||||
// Only update the snapshot if any new transactions were added
|
||||
|
|
@ -758,7 +781,7 @@ func (w *worker) resultLoop() {
|
|||
err error
|
||||
)
|
||||
|
||||
tracing.Exec(task.ctx, "resultLoop", func(ctx context.Context, span trace.Span) {
|
||||
tracing.Exec(task.ctx, "", "resultLoop", func(ctx context.Context, span trace.Span) {
|
||||
for i, taskReceipt := range task.receipts {
|
||||
receipt := new(types.Receipt)
|
||||
receipts[i] = receipt
|
||||
|
|
@ -782,8 +805,8 @@ func (w *worker) resultLoop() {
|
|||
}
|
||||
|
||||
// Commit block and state to database.
|
||||
tracing.ElapsedTime(ctx, span, "WriteBlockAndSetHead time taken", func(_ context.Context, _ trace.Span) {
|
||||
_, err = w.chain.WriteBlockAndSetHead(block, receipts, logs, task.state, true)
|
||||
tracing.Exec(ctx, "", "resultLoop.WriteBlockAndSetHead", func(ctx context.Context, span trace.Span) {
|
||||
_, err = w.chain.WriteBlockAndSetHead(ctx, block, receipts, logs, task.state, true)
|
||||
})
|
||||
|
||||
tracing.SetAttributes(
|
||||
|
|
@ -808,6 +831,12 @@ func (w *worker) resultLoop() {
|
|||
// Broadcast the block and announce chain insertion event
|
||||
w.mux.Post(core.NewMinedBlockEvent{Block: block})
|
||||
|
||||
sealedBlocksCounter.Inc(1)
|
||||
|
||||
if block.Transactions().Len() == 0 {
|
||||
sealedEmptyBlocksCounter.Inc(1)
|
||||
}
|
||||
|
||||
// Insert the block into the set of pending ones to resultLoop for confirmations
|
||||
w.unconfirmed.Insert(block.NumberU64(), block.Hash())
|
||||
case <-w.exitCh:
|
||||
|
|
@ -918,6 +947,22 @@ func (w *worker) commitTransactions(env *environment, txs *types.TransactionsByP
|
|||
}
|
||||
var coalescedLogs []*types.Log
|
||||
|
||||
initialGasLimit := env.gasPool.Gas()
|
||||
initialTxs := txs.GetTxs()
|
||||
|
||||
var breakCause string
|
||||
|
||||
defer func() {
|
||||
log.OnDebug(func(lg log.Logging) {
|
||||
lg("commitTransactions-stats",
|
||||
"initialTxsCount", initialTxs,
|
||||
"initialGasLimit", initialGasLimit,
|
||||
"resultTxsCount", txs.GetTxs(),
|
||||
"resultGapPool", env.gasPool.Gas(),
|
||||
"exitCause", breakCause)
|
||||
})
|
||||
}()
|
||||
|
||||
for {
|
||||
// In the following three cases, we will interrupt the execution of the transaction.
|
||||
// (1) new head block event arrival, the interrupt signal is 1
|
||||
|
|
@ -965,7 +1010,14 @@ func (w *worker) commitTransactions(env *environment, txs *types.TransactionsByP
|
|||
// Start executing the transaction
|
||||
env.state.Prepare(tx.Hash(), env.tcount)
|
||||
|
||||
var start time.Time
|
||||
|
||||
log.OnDebug(func(log.Logging) {
|
||||
start = time.Now()
|
||||
})
|
||||
|
||||
logs, err := w.commitTransaction(env, tx)
|
||||
|
||||
switch {
|
||||
case errors.Is(err, core.ErrGasLimitReached):
|
||||
// Pop the current out-of-gas transaction without shifting in the next from the account
|
||||
|
|
@ -988,6 +1040,10 @@ func (w *worker) commitTransactions(env *environment, txs *types.TransactionsByP
|
|||
env.tcount++
|
||||
txs.Shift()
|
||||
|
||||
log.OnDebug(func(lg log.Logging) {
|
||||
lg("Committed new tx", "tx hash", tx.Hash(), "from", from, "to", tx.To(), "nonce", tx.Nonce(), "gas", tx.Gas(), "gasPrice", tx.GasPrice(), "value", tx.Value(), "time spent", time.Since(start))
|
||||
})
|
||||
|
||||
case errors.Is(err, core.ErrTxTypeNotSupported):
|
||||
// Pop the unsupported transaction without shifting in the next from the account
|
||||
log.Trace("Skipping unsupported transaction type", "sender", from, "type", tx.Type())
|
||||
|
|
@ -1077,7 +1133,7 @@ func (w *worker) prepareWork(genParams *generateParams) (*environment, error) {
|
|||
}
|
||||
// Set baseFee and GasLimit if we are on an EIP-1559 chain
|
||||
if w.chainConfig.IsLondon(header.Number) {
|
||||
header.BaseFee = misc.CalcBaseFee(w.chainConfig, parent.Header())
|
||||
header.BaseFee = misc.CalcBaseFeeUint(w.chainConfig, parent.Header()).ToBig()
|
||||
if !w.chainConfig.IsLondon(parent.Number()) {
|
||||
parentGasLimit := parent.GasLimit() * params.ElasticityMultiplier
|
||||
header.GasLimit = core.CalcGasLimit(parentGasLimit, w.config.GasCeil)
|
||||
|
|
@ -1085,7 +1141,12 @@ func (w *worker) prepareWork(genParams *generateParams) (*environment, error) {
|
|||
}
|
||||
// Run the consensus preparation with the default or customized consensus engine.
|
||||
if err := w.engine.Prepare(w.chain, header); err != nil {
|
||||
switch err.(type) {
|
||||
case *bor.UnauthorizedSignerError:
|
||||
log.Debug("Failed to prepare header for sealing", "err", err)
|
||||
default:
|
||||
log.Error("Failed to prepare header for sealing", "err", err)
|
||||
}
|
||||
return nil, err
|
||||
}
|
||||
// Could potentially happen if starting to mine in an odd state.
|
||||
|
|
@ -1117,9 +1178,75 @@ func (w *worker) prepareWork(genParams *generateParams) (*environment, error) {
|
|||
return env, nil
|
||||
}
|
||||
|
||||
func startProfiler(profile string, filepath string, number uint64) (func() error, error) {
|
||||
var (
|
||||
buf bytes.Buffer
|
||||
err error
|
||||
)
|
||||
|
||||
closeFn := func() {}
|
||||
|
||||
switch profile {
|
||||
case "cpu":
|
||||
err = pprof.StartCPUProfile(&buf)
|
||||
|
||||
if err == nil {
|
||||
closeFn = func() {
|
||||
pprof.StopCPUProfile()
|
||||
}
|
||||
}
|
||||
case "trace":
|
||||
err = ptrace.Start(&buf)
|
||||
|
||||
if err == nil {
|
||||
closeFn = func() {
|
||||
ptrace.Stop()
|
||||
}
|
||||
}
|
||||
case "heap":
|
||||
runtime.GC()
|
||||
|
||||
err = pprof.WriteHeapProfile(&buf)
|
||||
default:
|
||||
log.Info("Incorrect profile name")
|
||||
}
|
||||
|
||||
if err != nil {
|
||||
return func() error {
|
||||
closeFn()
|
||||
return nil
|
||||
}, err
|
||||
}
|
||||
|
||||
closeFnNew := func() error {
|
||||
var err error
|
||||
|
||||
closeFn()
|
||||
|
||||
if buf.Len() == 0 {
|
||||
return nil
|
||||
}
|
||||
|
||||
f, err := os.Create(filepath + "/" + profile + "-" + fmt.Sprint(number) + ".prof")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
defer f.Close()
|
||||
|
||||
_, err = f.Write(buf.Bytes())
|
||||
|
||||
return err
|
||||
}
|
||||
|
||||
return closeFnNew, nil
|
||||
}
|
||||
|
||||
// fillTransactions retrieves the pending transactions from the txpool and fills them
|
||||
// into the given sealing block. The transaction selection and ordering strategy can
|
||||
// be customized with the plugin in the future.
|
||||
//
|
||||
//nolint:gocognit
|
||||
func (w *worker) fillTransactions(ctx context.Context, interrupt *int32, env *environment) {
|
||||
ctx, span := tracing.StartSpan(ctx, "fillTransactions")
|
||||
defer tracing.EndSpan(span)
|
||||
|
|
@ -1134,10 +1261,76 @@ func (w *worker) fillTransactions(ctx context.Context, interrupt *int32, env *en
|
|||
remoteTxs map[common.Address]types.Transactions
|
||||
)
|
||||
|
||||
tracing.Exec(ctx, "worker.SplittingTransactions", func(ctx context.Context, span trace.Span) {
|
||||
pending := w.eth.TxPool().Pending(true)
|
||||
// TODO: move to config or RPC
|
||||
const profiling = false
|
||||
|
||||
if profiling {
|
||||
doneCh := make(chan struct{})
|
||||
|
||||
defer func() {
|
||||
close(doneCh)
|
||||
}()
|
||||
|
||||
go func(number uint64) {
|
||||
closeFn := func() error {
|
||||
return nil
|
||||
}
|
||||
|
||||
for {
|
||||
select {
|
||||
case <-time.After(150 * time.Millisecond):
|
||||
// Check if we've not crossed limit
|
||||
if attempt := atomic.AddInt32(w.profileCount, 1); attempt >= 10 {
|
||||
log.Info("Completed profiling", "attempt", attempt)
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
log.Info("Starting profiling in fill transactions", "number", number)
|
||||
|
||||
dir, err := os.MkdirTemp("", fmt.Sprintf("bor-traces-%s-", time.Now().UTC().Format("2006-01-02-150405Z")))
|
||||
if err != nil {
|
||||
log.Error("Error in profiling", "path", dir, "number", number, "err", err)
|
||||
return
|
||||
}
|
||||
|
||||
// grab the cpu profile
|
||||
closeFnInternal, err := startProfiler("cpu", dir, number)
|
||||
if err != nil {
|
||||
log.Error("Error in profiling", "path", dir, "number", number, "err", err)
|
||||
return
|
||||
}
|
||||
|
||||
closeFn = func() error {
|
||||
err := closeFnInternal()
|
||||
|
||||
log.Info("Completed profiling", "path", dir, "number", number, "error", err)
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
case <-doneCh:
|
||||
err := closeFn()
|
||||
|
||||
if err != nil {
|
||||
log.Info("closing fillTransactions", "number", number, "error", err)
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
}
|
||||
}(env.header.Number.Uint64())
|
||||
}
|
||||
|
||||
tracing.Exec(ctx, "", "worker.SplittingTransactions", func(ctx context.Context, span trace.Span) {
|
||||
|
||||
prePendingTime := time.Now()
|
||||
|
||||
pending := w.eth.TxPool().Pending(ctx, true)
|
||||
remoteTxs = pending
|
||||
|
||||
postPendingTime := time.Now()
|
||||
|
||||
for _, account := range w.eth.TxPool().Locals() {
|
||||
if txs := remoteTxs[account]; len(txs) > 0 {
|
||||
delete(remoteTxs, account)
|
||||
|
|
@ -1145,6 +1338,8 @@ func (w *worker) fillTransactions(ctx context.Context, interrupt *int32, env *en
|
|||
}
|
||||
}
|
||||
|
||||
postLocalsTime := time.Now()
|
||||
|
||||
localTxsCount = len(localTxs)
|
||||
remoteTxsCount = len(remoteTxs)
|
||||
|
||||
|
|
@ -1152,6 +1347,8 @@ func (w *worker) fillTransactions(ctx context.Context, interrupt *int32, env *en
|
|||
span,
|
||||
attribute.Int("len of local txs", localTxsCount),
|
||||
attribute.Int("len of remote txs", remoteTxsCount),
|
||||
attribute.String("time taken by Pending()", fmt.Sprintf("%v", postPendingTime.Sub(prePendingTime))),
|
||||
attribute.String("time taken by Locals()", fmt.Sprintf("%v", postLocalsTime.Sub(postPendingTime))),
|
||||
)
|
||||
})
|
||||
|
||||
|
|
@ -1164,8 +1361,8 @@ func (w *worker) fillTransactions(ctx context.Context, interrupt *int32, env *en
|
|||
if localTxsCount > 0 {
|
||||
var txs *types.TransactionsByPriceAndNonce
|
||||
|
||||
tracing.Exec(ctx, "worker.LocalTransactionsByPriceAndNonce", func(ctx context.Context, span trace.Span) {
|
||||
txs = types.NewTransactionsByPriceAndNonce(env.signer, localTxs, env.header.BaseFee)
|
||||
tracing.Exec(ctx, "", "worker.LocalTransactionsByPriceAndNonce", func(ctx context.Context, span trace.Span) {
|
||||
txs = types.NewTransactionsByPriceAndNonce(env.signer, localTxs, cmath.FromBig(env.header.BaseFee))
|
||||
|
||||
tracing.SetAttributes(
|
||||
span,
|
||||
|
|
@ -1173,7 +1370,7 @@ func (w *worker) fillTransactions(ctx context.Context, interrupt *int32, env *en
|
|||
)
|
||||
})
|
||||
|
||||
tracing.Exec(ctx, "worker.LocalCommitTransactions", func(ctx context.Context, span trace.Span) {
|
||||
tracing.Exec(ctx, "", "worker.LocalCommitTransactions", func(ctx context.Context, span trace.Span) {
|
||||
committed = w.commitTransactions(env, txs, interrupt)
|
||||
})
|
||||
|
||||
|
|
@ -1187,8 +1384,8 @@ func (w *worker) fillTransactions(ctx context.Context, interrupt *int32, env *en
|
|||
if remoteTxsCount > 0 {
|
||||
var txs *types.TransactionsByPriceAndNonce
|
||||
|
||||
tracing.Exec(ctx, "worker.RemoteTransactionsByPriceAndNonce", func(ctx context.Context, span trace.Span) {
|
||||
txs = types.NewTransactionsByPriceAndNonce(env.signer, remoteTxs, env.header.BaseFee)
|
||||
tracing.Exec(ctx, "", "worker.RemoteTransactionsByPriceAndNonce", func(ctx context.Context, span trace.Span) {
|
||||
txs = types.NewTransactionsByPriceAndNonce(env.signer, remoteTxs, cmath.FromBig(env.header.BaseFee))
|
||||
|
||||
tracing.SetAttributes(
|
||||
span,
|
||||
|
|
@ -1196,7 +1393,7 @@ func (w *worker) fillTransactions(ctx context.Context, interrupt *int32, env *en
|
|||
)
|
||||
})
|
||||
|
||||
tracing.Exec(ctx, "worker.RemoteCommitTransactions", func(ctx context.Context, span trace.Span) {
|
||||
tracing.Exec(ctx, "", "worker.RemoteCommitTransactions", func(ctx context.Context, span trace.Span) {
|
||||
committed = w.commitTransactions(env, txs, interrupt)
|
||||
})
|
||||
|
||||
|
|
@ -1237,7 +1434,7 @@ func (w *worker) commitWork(ctx context.Context, interrupt *int32, noempty bool,
|
|||
err error
|
||||
)
|
||||
|
||||
tracing.Exec(ctx, "worker.prepareWork", func(ctx context.Context, span trace.Span) {
|
||||
tracing.Exec(ctx, "", "worker.prepareWork", func(ctx context.Context, span trace.Span) {
|
||||
// Set the coinbase if the worker is running or it's required
|
||||
var coinbase common.Address
|
||||
if w.isRunning() {
|
||||
|
|
|
|||
|
|
@ -75,7 +75,7 @@ func testGenerateBlockAndImport(t *testing.T, isClique bool, isBor bool) {
|
|||
ethAPIMock.EXPECT().Call(gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any()).AnyTimes()
|
||||
|
||||
spanner := bor.NewMockSpanner(ctrl)
|
||||
spanner.EXPECT().GetCurrentValidators(gomock.Any(), gomock.Any(), gomock.Any()).Return([]*valset.Validator{
|
||||
spanner.EXPECT().GetCurrentValidatorsByHash(gomock.Any(), gomock.Any(), gomock.Any()).Return([]*valset.Validator{
|
||||
{
|
||||
ID: 0,
|
||||
Address: TestBankAddress,
|
||||
|
|
@ -622,7 +622,7 @@ func BenchmarkBorMining(b *testing.B) {
|
|||
ethAPIMock.EXPECT().Call(gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any()).AnyTimes()
|
||||
|
||||
spanner := bor.NewMockSpanner(ctrl)
|
||||
spanner.EXPECT().GetCurrentValidators(gomock.Any(), gomock.Any(), gomock.Any()).Return([]*valset.Validator{
|
||||
spanner.EXPECT().GetCurrentValidatorsByHash(gomock.Any(), gomock.Any(), gomock.Any()).Return([]*valset.Validator{
|
||||
{
|
||||
ID: 0,
|
||||
Address: TestBankAddress,
|
||||
|
|
|
|||
|
|
@ -57,15 +57,19 @@ func TestClientSyncTree(t *testing.T) {
|
|||
|
||||
c := NewClient(Config{Resolver: r, Logger: testlog.Logger(t, log.LvlTrace)})
|
||||
stree, err := c.SyncTree("enrtree://AKPYQIUQIL7PSIACI32J7FGZW56E5FKHEFCCOFHILBIMW3M6LWXS2@n")
|
||||
|
||||
if err != nil {
|
||||
t.Fatal("sync error:", err)
|
||||
}
|
||||
|
||||
if !reflect.DeepEqual(sortByID(stree.Nodes()), sortByID(wantNodes)) {
|
||||
t.Errorf("wrong nodes in synced tree:\nhave %v\nwant %v", spew.Sdump(stree.Nodes()), spew.Sdump(wantNodes))
|
||||
}
|
||||
|
||||
if !reflect.DeepEqual(stree.Links(), wantLinks) {
|
||||
t.Errorf("wrong links in synced tree: %v", stree.Links())
|
||||
}
|
||||
|
||||
if stree.Seq() != wantSeq {
|
||||
t.Errorf("synced tree has wrong seq: %d", stree.Seq())
|
||||
}
|
||||
|
|
@ -295,7 +299,7 @@ func TestIteratorEmptyTree(t *testing.T) {
|
|||
|
||||
// updateSomeNodes applies ENR updates to some of the given nodes.
|
||||
func updateSomeNodes(keySeed int64, nodes []*enode.Node) {
|
||||
keys := testKeys(nodesSeed1, len(nodes))
|
||||
keys := testKeys(keySeed, len(nodes))
|
||||
for i, n := range nodes[:len(nodes)/2] {
|
||||
r := n.Record()
|
||||
r.Set(enr.IP{127, 0, 0, 1})
|
||||
|
|
@ -384,10 +388,12 @@ func makeTestTree(domain string, nodes []*enode.Node, links []string) (*Tree, st
|
|||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
url, err := tree.Sign(testKey(signingKeySeed), domain)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
return tree, url
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -86,7 +86,7 @@ gcmode = "archive"
|
|||
# vhosts = ["*"]
|
||||
# corsdomain = ["*"]
|
||||
# [jsonrpc.timeouts]
|
||||
# read = "30s"
|
||||
# read = "10s"
|
||||
# write = "30s"
|
||||
# idle = "2m0s"
|
||||
|
||||
|
|
|
|||
|
|
@ -86,7 +86,7 @@ syncmode = "full"
|
|||
# vhosts = ["*"]
|
||||
# corsdomain = ["*"]
|
||||
# [jsonrpc.timeouts]
|
||||
# read = "30s"
|
||||
# read = "10s"
|
||||
# write = "30s"
|
||||
# idle = "2m0s"
|
||||
|
||||
|
|
|
|||
|
|
@ -88,7 +88,7 @@ syncmode = "full"
|
|||
# vhosts = ["*"]
|
||||
# corsdomain = ["*"]
|
||||
# [jsonrpc.timeouts]
|
||||
# read = "30s"
|
||||
# read = "10s"
|
||||
# write = "30s"
|
||||
# idle = "2m0s"
|
||||
|
||||
|
|
|
|||
|
|
@ -88,7 +88,7 @@ syncmode = "full"
|
|||
# vhosts = ["*"]
|
||||
# corsdomain = ["*"]
|
||||
# [jsonrpc.timeouts]
|
||||
# read = "30s"
|
||||
# read = "10s"
|
||||
# write = "30s"
|
||||
# idle = "2m0s"
|
||||
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
Source: bor
|
||||
Version: 0.3.4-beta3
|
||||
Version: 0.3.8-beta
|
||||
Section: develop
|
||||
Priority: standard
|
||||
Maintainer: Polygon <release-team@polygon.technology>
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
Source: bor
|
||||
Version: 0.3.4-beta3
|
||||
Version: 0.3.8-beta
|
||||
Section: develop
|
||||
Priority: standard
|
||||
Maintainer: Polygon <release-team@polygon.technology>
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
Source: bor-profile
|
||||
Version: 0.3.4-beta3
|
||||
Version: 0.3.8-beta
|
||||
Section: develop
|
||||
Priority: standard
|
||||
Maintainer: Polygon <release-team@polygon.technology>
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
Source: bor-profile
|
||||
Version: 0.3.4-beta3
|
||||
Version: 0.3.8-beta
|
||||
Section: develop
|
||||
Priority: standard
|
||||
Maintainer: Polygon <release-team@polygon.technology>
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
Source: bor-profile
|
||||
Version: 0.3.4-beta3
|
||||
Version: 0.3.8-beta
|
||||
Section: develop
|
||||
Priority: standard
|
||||
Maintainer: Polygon <release-team@polygon.technology>
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
Source: bor-profile
|
||||
Version: 0.3.4-beta3
|
||||
Version: 0.3.8-beta
|
||||
Section: develop
|
||||
Priority: standard
|
||||
Maintainer: Polygon <release-team@polygon.technology>
|
||||
|
|
|
|||
|
|
@ -86,7 +86,7 @@ gcmode = "archive"
|
|||
# vhosts = ["*"]
|
||||
# corsdomain = ["*"]
|
||||
# [jsonrpc.timeouts]
|
||||
# read = "30s"
|
||||
# read = "10s"
|
||||
# write = "30s"
|
||||
# idle = "2m0s"
|
||||
|
||||
|
|
|
|||
|
|
@ -86,7 +86,7 @@ syncmode = "full"
|
|||
# vhosts = ["*"]
|
||||
# corsdomain = ["*"]
|
||||
# [jsonrpc.timeouts]
|
||||
# read = "30s"
|
||||
# read = "10s"
|
||||
# write = "30s"
|
||||
# idle = "2m0s"
|
||||
|
||||
|
|
|
|||
|
|
@ -88,7 +88,7 @@ syncmode = "full"
|
|||
# vhosts = ["*"]
|
||||
# corsdomain = ["*"]
|
||||
# [jsonrpc.timeouts]
|
||||
# read = "30s"
|
||||
# read = "10s"
|
||||
# write = "30s"
|
||||
# idle = "2m0s"
|
||||
|
||||
|
|
|
|||
|
|
@ -88,7 +88,7 @@ syncmode = "full"
|
|||
# vhosts = ["*"]
|
||||
# corsdomain = ["*"]
|
||||
# [jsonrpc.timeouts]
|
||||
# read = "30s"
|
||||
# read = "10s"
|
||||
# write = "30s"
|
||||
# idle = "2m0s"
|
||||
|
||||
|
|
|
|||
|
|
@ -23,8 +23,8 @@ import (
|
|||
const (
|
||||
VersionMajor = 0 // Major version component of the current release
|
||||
VersionMinor = 3 // Minor version component of the current release
|
||||
VersionPatch = 4 // Patch version component of the current release
|
||||
VersionMeta = "beta3" // Version metadata to append to the version string
|
||||
VersionPatch = 8 // Patch version component of the current release
|
||||
VersionMeta = "beta" // Version metadata to append to the version string
|
||||
)
|
||||
|
||||
// Version holds the textual version string.
|
||||
|
|
|
|||
|
|
@ -104,7 +104,7 @@ type HTTPTimeouts struct {
|
|||
// DefaultHTTPTimeouts represents the default timeout values used if further
|
||||
// configuration is not provided.
|
||||
var DefaultHTTPTimeouts = HTTPTimeouts{
|
||||
ReadTimeout: 30 * time.Second,
|
||||
ReadTimeout: 10 * time.Second,
|
||||
WriteTimeout: 30 * time.Second,
|
||||
IdleTimeout: 120 * time.Second,
|
||||
}
|
||||
|
|
|
|||
|
|
@ -392,12 +392,18 @@ func TestInsertingSpanSizeBlocks(t *testing.T) {
|
|||
|
||||
currentValidators := []*valset.Validator{valset.NewValidator(addr, 10)}
|
||||
|
||||
spanner := getMockedSpanner(t, currentValidators)
|
||||
_bor.SetSpanner(spanner)
|
||||
|
||||
// Insert sprintSize # of blocks so that span is fetched at the start of a new sprint
|
||||
for i := uint64(1); i <= spanSize; i++ {
|
||||
block = buildNextBlock(t, _bor, chain, block, nil, init.genesis.Config.Bor, nil, currentValidators)
|
||||
insertNewBlock(t, chain, block)
|
||||
}
|
||||
|
||||
spanner = getMockedSpanner(t, currentSpan.ValidatorSet.Validators)
|
||||
_bor.SetSpanner(spanner)
|
||||
|
||||
validators, err := _bor.GetCurrentValidators(context.Background(), block.Hash(), spanSize) // check validator set at the first block of new span
|
||||
if err != nil {
|
||||
t.Fatalf("%s", err)
|
||||
|
|
@ -427,6 +433,9 @@ func TestFetchStateSyncEvents(t *testing.T) {
|
|||
|
||||
currentValidators := []*valset.Validator{valset.NewValidator(addr, 10)}
|
||||
|
||||
spanner := getMockedSpanner(t, currentValidators)
|
||||
_bor.SetSpanner(spanner)
|
||||
|
||||
// Insert sprintSize # of blocks so that span is fetched at the start of a new sprint
|
||||
for i := uint64(1); i < sprintSize; i++ {
|
||||
if IsSpanEnd(i) {
|
||||
|
|
@ -528,6 +537,9 @@ func TestFetchStateSyncEvents_2(t *testing.T) {
|
|||
currentValidators = []*valset.Validator{valset.NewValidator(addr, 10)}
|
||||
}
|
||||
|
||||
spanner := getMockedSpanner(t, currentValidators)
|
||||
_bor.SetSpanner(spanner)
|
||||
|
||||
block = buildNextBlock(t, _bor, chain, block, nil, init.genesis.Config.Bor, nil, currentValidators)
|
||||
insertNewBlock(t, chain, block)
|
||||
}
|
||||
|
|
@ -554,6 +566,9 @@ func TestFetchStateSyncEvents_2(t *testing.T) {
|
|||
currentValidators = []*valset.Validator{valset.NewValidator(addr, 10)}
|
||||
}
|
||||
|
||||
spanner := getMockedSpanner(t, currentValidators)
|
||||
_bor.SetSpanner(spanner)
|
||||
|
||||
block = buildNextBlock(t, _bor, chain, block, nil, init.genesis.Config.Bor, nil, res.Result.ValidatorSet.Validators)
|
||||
insertNewBlock(t, chain, block)
|
||||
}
|
||||
|
|
@ -580,6 +595,8 @@ func TestOutOfTurnSigning(t *testing.T) {
|
|||
|
||||
h.EXPECT().Close().AnyTimes()
|
||||
|
||||
spanner := getMockedSpanner(t, heimdallSpan.ValidatorSet.Validators)
|
||||
_bor.SetSpanner(spanner)
|
||||
_bor.SetHeimdallClient(h)
|
||||
|
||||
db := init.ethereum.ChainDb()
|
||||
|
|
@ -1082,6 +1099,9 @@ func TestJaipurFork(t *testing.T) {
|
|||
|
||||
res, _ := loadSpanFromFile(t)
|
||||
|
||||
spanner := getMockedSpanner(t, res.Result.ValidatorSet.Validators)
|
||||
_bor.SetSpanner(spanner)
|
||||
|
||||
for i := uint64(1); i < sprintSize; i++ {
|
||||
block = buildNextBlock(t, _bor, chain, block, nil, init.genesis.Config.Bor, nil, res.Result.ValidatorSet.Validators)
|
||||
insertNewBlock(t, chain, block)
|
||||
|
|
|
|||
|
|
@ -352,6 +352,17 @@ func getMockedHeimdallClient(t *testing.T, heimdallSpan *span.HeimdallSpan) (*mo
|
|||
return h, ctrl
|
||||
}
|
||||
|
||||
func getMockedSpanner(t *testing.T, validators []*valset.Validator) *bor.MockSpanner {
|
||||
t.Helper()
|
||||
|
||||
spanner := bor.NewMockSpanner(gomock.NewController(t))
|
||||
spanner.EXPECT().GetCurrentValidatorsByHash(gomock.Any(), gomock.Any(), gomock.Any()).Return(validators, nil).AnyTimes()
|
||||
spanner.EXPECT().GetCurrentValidatorsByBlockNrOrHash(gomock.Any(), gomock.Any(), gomock.Any()).Return(validators, nil).AnyTimes()
|
||||
spanner.EXPECT().GetCurrentSpan(gomock.Any(), gomock.Any()).Return(&span.Span{0, 0, 0}, nil).AnyTimes()
|
||||
spanner.EXPECT().CommitSpan(gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any()).Return(nil).AnyTimes()
|
||||
return spanner
|
||||
}
|
||||
|
||||
func generateFakeStateSyncEvents(sample *clerk.EventRecordWithTime, count int) []*clerk.EventRecordWithTime {
|
||||
events := make([]*clerk.EventRecordWithTime, count)
|
||||
event := *sample
|
||||
|
|
|
|||
|
|
@ -141,9 +141,6 @@ func (tm *testMatcher) findSkip(name string) (reason string, skipload bool) {
|
|||
isWin32 := runtime.GOARCH == "386" && runtime.GOOS == "windows"
|
||||
for _, re := range tm.slowpat {
|
||||
if re.MatchString(name) {
|
||||
if testing.Short() {
|
||||
return "skipped in -short mode", false
|
||||
}
|
||||
if isWin32 {
|
||||
return "skipped on 32bit windows", false
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in a new issue