Merge branch 'master' into goja-2

This commit is contained in:
ucwong 2023-08-14 11:23:17 +01:00 committed by GitHub
commit 2a16a6eac3
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
78 changed files with 855 additions and 553 deletions

View file

@ -40,8 +40,8 @@ import (
const minReloadInterval = 2 * time.Second
// byURL defines the sorting order for accounts.
func byURL(a, b accounts.Account) bool {
return a.URL.Cmp(b.URL) < 0
func byURL(a, b accounts.Account) int {
return a.URL.Cmp(b.URL)
}
// AmbiguousAddrError is returned when attempting to unlock

View file

@ -200,6 +200,7 @@ func doInstall(cmdline []string) {
staticlink = flag.Bool("static", false, "Create statically-linked executable")
)
flag.CommandLine.Parse(cmdline)
env := build.Env()
// Configure the toolchain.
tc := build.GoToolchain{GOARCH: *arch, CC: *cc}
@ -207,12 +208,16 @@ func doInstall(cmdline []string) {
csdb := build.MustLoadChecksums("build/checksums.txt")
tc.Root = build.DownloadGo(csdb, dlgoVersion)
}
// Disable CLI markdown doc generation in release builds and enable linking
// the CKZG library since we can make it portable here.
buildTags := []string{"urfave_cli_no_docs", "ckzg"}
// Disable CLI markdown doc generation in release builds.
buildTags := []string{"urfave_cli_no_docs"}
// Enable linking the CKZG library since we can make it work with additional flags.
if env.UbuntuVersion != "trusty" {
buildTags = append(buildTags, "ckzg")
}
// Configure the build.
env := build.Env()
gobuild := tc.Go("build", buildFlags(env, *staticlink, buildTags)...)
// arm64 CI builders are memory-constrained and can't handle concurrent builds,
@ -298,10 +303,14 @@ func doTest(cmdline []string) {
csdb := build.MustLoadChecksums("build/checksums.txt")
tc.Root = build.DownloadGo(csdb, dlgoVersion)
}
gotest := tc.Go("test", "-tags=ckzg")
gotest := tc.Go("test")
// CI needs a bit more time for the statetests (default 10m).
gotest.Args = append(gotest.Args, "-timeout=20m")
// Enable CKZG backend in CI.
gotest.Args = append(gotest.Args, "-tags=ckzg")
// Test a single package at a time. CI builders are slow
// and some tests run into timeouts under load.
gotest.Args = append(gotest.Args, "-p", "1")

View file

@ -28,7 +28,7 @@ override_dh_auto_build:
mv .mod $(GOPATH)/pkg/mod
# A fresh Go was built, all dependency downloads faked, hope build works now
../.go/bin/go run build/ci.go install -git-commit={{.Env.Commit}} -git-branch={{.Env.Branch}} -git-tag={{.Env.Tag}} -buildnum={{.Env.Buildnum}} -pull-request={{.Env.IsPullRequest}}
../.go/bin/go run build/ci.go install -git-commit={{.Env.Commit}} -git-branch={{.Env.Branch}} -git-tag={{.Env.Tag}} -buildnum={{.Env.Buildnum}} -pull-request={{.Env.IsPullRequest}} -ubuntu {{.Distro}}
override_dh_auto_test:

View file

@ -288,11 +288,17 @@ func makeDeletionChanges(records map[string]recordSet, keep map[string]string) [
// sortChanges ensures DNS changes are in leaf-added -> root-changed -> leaf-deleted order.
func sortChanges(changes []types.Change) {
score := map[string]int{"CREATE": 1, "UPSERT": 2, "DELETE": 3}
slices.SortFunc(changes, func(a, b types.Change) bool {
slices.SortFunc(changes, func(a, b types.Change) int {
if a.Action == b.Action {
return *a.ResourceRecordSet.Name < *b.ResourceRecordSet.Name
return strings.Compare(*a.ResourceRecordSet.Name, *b.ResourceRecordSet.Name)
}
return score[string(a.Action)] < score[string(b.Action)]
if score[string(a.Action)] < score[string(b.Action)] {
return -1
}
if score[string(a.Action)] > score[string(b.Action)] {
return 1
}
return 0
})
}

View file

@ -77,8 +77,8 @@ func (ns nodeSet) nodes() []*enode.Node {
result = append(result, n.N)
}
// Sort by ID.
slices.SortFunc(result, func(a, b *enode.Node) bool {
return bytes.Compare(a.ID().Bytes(), b.ID().Bytes()) < 0
slices.SortFunc(result, func(a, b *enode.Node) int {
return bytes.Compare(a.ID().Bytes(), b.ID().Bytes())
})
return result
}
@ -103,8 +103,14 @@ func (ns nodeSet) topN(n int) nodeSet {
for _, v := range ns {
byscore = append(byscore, v)
}
slices.SortFunc(byscore, func(a, b nodeJSON) bool {
return a.Score >= b.Score
slices.SortFunc(byscore, func(a, b nodeJSON) int {
if a.Score > b.Score {
return -1
}
if a.Score < b.Score {
return 1
}
return 0
})
result := make(nodeSet, n)
for _, v := range byscore[:n] {

View file

@ -65,9 +65,9 @@ func BigToHash(b *big.Int) Hash { return BytesToHash(b.Bytes()) }
// If b is larger than len(h), b will be cropped from the left.
func HexToHash(s string) Hash { return BytesToHash(FromHex(s)) }
// Less compares two hashes.
func (h Hash) Less(other Hash) bool {
return bytes.Compare(h[:], other[:]) < 0
// Cmp compares two hashes.
func (h Hash) Cmp(other Hash) int {
return bytes.Compare(h[:], other[:])
}
// Bytes gets the byte representation of the underlying hash.
@ -231,9 +231,9 @@ func IsHexAddress(s string) bool {
return len(s) == 2*AddressLength && isHex(s)
}
// Less compares two addresses.
func (a Address) Less(other Address) bool {
return bytes.Compare(a[:], other[:]) < 0
// Cmp compares two addresses.
func (a Address) Cmp(other Address) int {
return bytes.Compare(a[:], other[:])
}
// Bytes gets the string representation of the underlying address.

View file

@ -308,7 +308,7 @@ func (s *Snapshot) signers() []common.Address {
for sig := range s.Signers {
sigs = append(sigs, sig)
}
slices.SortFunc(sigs, common.Address.Less)
slices.SortFunc(sigs, common.Address.Cmp)
return sigs
}

View file

@ -53,7 +53,7 @@ func (ap *testerAccountPool) checkpoint(header *types.Header, signers []string)
for i, signer := range signers {
auths[i] = ap.address(signer)
}
slices.SortFunc(auths, common.Address.Less)
slices.SortFunc(auths, common.Address.Cmp)
for i, auth := range auths {
copy(header.Extra[extraVanity+i*common.AddressLength:], auth.Bytes())
}

View file

@ -68,6 +68,7 @@ func (v *BlockValidator) ValidateBody(block *types.Block) error {
if hash := types.DeriveSha(block.Transactions(), trie.NewStackTrie(nil)); hash != header.TxHash {
return fmt.Errorf("transaction root hash mismatch (header value %x, calculated %x)", header.TxHash, hash)
}
// Withdrawals are present after the Shanghai fork.
if header.WithdrawalsHash != nil {
// Withdrawals list must be present in body after Shanghai.
@ -81,14 +82,23 @@ func (v *BlockValidator) ValidateBody(block *types.Block) error {
// Withdrawals are not allowed prior to Shanghai fork
return errors.New("withdrawals present in block body")
}
// Blob transactions may be present after the Cancun fork.
var blobs int
for _, tx := range block.Transactions() {
for i, tx := range block.Transactions() {
// Count the number of blobs to validate against the header's blobGasUsed
blobs += len(tx.BlobHashes())
// If the tx is a blob tx, it must NOT have a sidecar attached to be valid in a block.
if tx.BlobTxSidecar() != nil {
return fmt.Errorf("unexpected blob sidecar in transaction at index %d", i)
}
// The individual checks for blob validity (version-check + not empty)
// happens in the state_transition check.
// happens in StateTransition.
}
// Check blob gas usage.
if header.BlobGasUsed != nil {
if want := *header.BlobGasUsed / params.BlobTxBlobGasPerBlob; uint64(blobs) != want { // div because the header is surely good vs the body might be bloated
return fmt.Errorf("blob gas used mismatch (header %v, calculated %v)", *header.BlobGasUsed, blobs*params.BlobTxBlobGasPerBlob)
@ -98,6 +108,8 @@ func (v *BlockValidator) ValidateBody(block *types.Block) error {
return errors.New("data blobs present in block body")
}
}
// Ancestor block must be known.
if !v.bc.HasBlockAndState(block.ParentHash(), block.NumberU64()-1) {
if !v.bc.HasBlock(block.ParentHash(), block.NumberU64()-1) {
return consensus.ErrUnknownAncestor

View file

@ -1053,8 +1053,8 @@ func (bc *BlockChain) procFutureBlocks() {
}
}
if len(blocks) > 0 {
slices.SortFunc(blocks, func(a, b *types.Block) bool {
return a.NumberU64() < b.NumberU64()
slices.SortFunc(blocks, func(a, b *types.Block) int {
return a.Number().Cmp(b.Number())
})
// Insert one by one as chain insertion needs contiguous ancestry between blocks
for i := range blocks {
@ -1085,19 +1085,30 @@ func (bc *BlockChain) InsertReceiptChain(blockChain types.Blocks, receiptChain [
ancientReceipts, liveReceipts []types.Receipts
)
// Do a sanity check that the provided chain is actually ordered and linked
for i := 0; i < len(blockChain); i++ {
for i, block := range blockChain {
if i != 0 {
if blockChain[i].NumberU64() != blockChain[i-1].NumberU64()+1 || blockChain[i].ParentHash() != blockChain[i-1].Hash() {
log.Error("Non contiguous receipt insert", "number", blockChain[i].Number(), "hash", blockChain[i].Hash(), "parent", blockChain[i].ParentHash(),
"prevnumber", blockChain[i-1].Number(), "prevhash", blockChain[i-1].Hash())
return 0, fmt.Errorf("non contiguous insert: item %d is #%d [%x..], item %d is #%d [%x..] (parent [%x..])", i-1, blockChain[i-1].NumberU64(),
blockChain[i-1].Hash().Bytes()[:4], i, blockChain[i].NumberU64(), blockChain[i].Hash().Bytes()[:4], blockChain[i].ParentHash().Bytes()[:4])
prev := blockChain[i-1]
if block.NumberU64() != prev.NumberU64()+1 || block.ParentHash() != prev.Hash() {
log.Error("Non contiguous receipt insert",
"number", block.Number(), "hash", block.Hash(), "parent", block.ParentHash(),
"prevnumber", prev.Number(), "prevhash", prev.Hash())
return 0, fmt.Errorf("non contiguous insert: item %d is #%d [%x..], item %d is #%d [%x..] (parent [%x..])",
i-1, prev.NumberU64(), prev.Hash().Bytes()[:4],
i, block.NumberU64(), block.Hash().Bytes()[:4], block.ParentHash().Bytes()[:4])
}
}
if blockChain[i].NumberU64() <= ancientLimit {
ancientBlocks, ancientReceipts = append(ancientBlocks, blockChain[i]), append(ancientReceipts, receiptChain[i])
if block.NumberU64() <= ancientLimit {
ancientBlocks, ancientReceipts = append(ancientBlocks, block), append(ancientReceipts, receiptChain[i])
} else {
liveBlocks, liveReceipts = append(liveBlocks, blockChain[i]), append(liveReceipts, receiptChain[i])
liveBlocks, liveReceipts = append(liveBlocks, block), append(liveReceipts, receiptChain[i])
}
// Here we also validate that blob transactions in the block do not contain a sidecar.
// While the sidecar does not affect the block hash / tx hash, sending blobs within a block is not allowed.
for txIndex, tx := range block.Transactions() {
if tx.Type() == types.BlobTxType && tx.BlobTxSidecar() != nil {
return 0, fmt.Errorf("block #%d contains unexpected blob sidecar in tx at index %d", block.NumberU64(), txIndex)
}
}
}

View file

@ -902,9 +902,9 @@ func WriteBadBlock(db ethdb.KeyValueStore, block *types.Block) {
Header: block.Header(),
Body: block.Body(),
})
slices.SortFunc(badBlocks, func(a, b *badBlock) bool {
slices.SortFunc(badBlocks, func(a, b *badBlock) int {
// Note: sorting in descending number order.
return a.Header.Number.Uint64() >= b.Header.Number.Uint64()
return -a.Header.Number.Cmp(b.Header.Number)
})
if len(badBlocks) > badBlockToKeep {
badBlocks = badBlocks[:badBlockToKeep]

View file

@ -19,12 +19,12 @@ package rawdb
import (
"math/big"
"reflect"
"sort"
"sync"
"testing"
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/core/types"
"golang.org/x/exp/slices"
)
func TestChainIterator(t *testing.T) {
@ -92,11 +92,9 @@ func TestChainIterator(t *testing.T) {
}
}
if !c.reverse {
slices.Sort(numbers)
sort.Ints(numbers)
} else {
slices.SortFunc(numbers, func(a, b int) bool {
return a > b // Sort descending
})
sort.Sort(sort.Reverse(sort.IntSlice(numbers)))
}
if !reflect.DeepEqual(numbers, c.expect) {
t.Fatalf("Case %d failed, visit element mismatch, want %v, got %v", i, c.expect, numbers)

View file

@ -525,7 +525,7 @@ func (dl *diffLayer) AccountList() []common.Hash {
dl.accountList = append(dl.accountList, hash)
}
}
slices.SortFunc(dl.accountList, common.Hash.Less)
slices.SortFunc(dl.accountList, common.Hash.Cmp)
dl.memory += uint64(len(dl.accountList) * common.HashLength)
return dl.accountList
}
@ -563,7 +563,7 @@ func (dl *diffLayer) StorageList(accountHash common.Hash) ([]common.Hash, bool)
for k := range storageMap {
storageList = append(storageList, k)
}
slices.SortFunc(storageList, common.Hash.Less)
slices.SortFunc(storageList, common.Hash.Cmp)
dl.storageList[accountHash] = storageList
dl.memory += uint64(len(dl.storageList)*common.HashLength + common.HashLength)
return storageList, destructed

View file

@ -33,19 +33,25 @@ type weightedIterator struct {
priority int
}
func (it *weightedIterator) Less(other *weightedIterator) bool {
func (it *weightedIterator) Cmp(other *weightedIterator) int {
// Order the iterators primarily by the account hashes
hashI := it.it.Hash()
hashJ := other.it.Hash()
switch bytes.Compare(hashI[:], hashJ[:]) {
case -1:
return true
return -1
case 1:
return false
return 1
}
// Same account/storage-slot in multiple layers, split by priority
return it.priority < other.priority
if it.priority < other.priority {
return -1
}
if it.priority > other.priority {
return 1
}
return 0
}
// fastIterator is a more optimized multi-layer iterator which maintains a
@ -155,9 +161,7 @@ func (fi *fastIterator) init() {
}
}
// Re-sort the entire list
slices.SortFunc(fi.iterators, func(a, b *weightedIterator) bool {
return a.Less(b)
})
slices.SortFunc(fi.iterators, func(a, b *weightedIterator) int { return a.Cmp(b) })
fi.initiated = false
}

View file

@ -19,6 +19,7 @@ package blobpool
import (
"container/heap"
"errors"
"fmt"
"math"
"math/big"
@ -35,7 +36,6 @@ import (
"github.com/ethereum/go-ethereum/core/state"
"github.com/ethereum/go-ethereum/core/txpool"
"github.com/ethereum/go-ethereum/core/types"
"github.com/ethereum/go-ethereum/crypto/kzg4844"
"github.com/ethereum/go-ethereum/event"
"github.com/ethereum/go-ethereum/log"
"github.com/ethereum/go-ethereum/metrics"
@ -83,16 +83,6 @@ const (
limboedTransactionStore = "limbo"
)
// blobTx is a wrapper around types.BlobTx which also contains the literal blob
// data along with all the transaction metadata.
type blobTx struct {
Tx *types.Transaction
Blobs []kzg4844.Blob
Commits []kzg4844.Commitment
Proofs []kzg4844.Proof
}
// blobTxMeta is the minimal subset of types.BlobTx necessary to validate and
// schedule the blob transactions into the following blocks. Only ever add the
// bare minimum needed fields to keep the size down (and thus number of entries
@ -455,22 +445,27 @@ func (p *BlobPool) Close() error {
// parseTransaction is a callback method on pool creation that gets called for
// each transaction on disk to create the in-memory metadata index.
func (p *BlobPool) parseTransaction(id uint64, size uint32, blob []byte) error {
item := new(blobTx)
if err := rlp.DecodeBytes(blob, item); err != nil {
tx := new(types.Transaction)
if err := rlp.DecodeBytes(blob, tx); err != nil {
// This path is impossible unless the disk data representation changes
// across restarts. For that ever unprobable case, recover gracefully
// by ignoring this data entry.
log.Error("Failed to decode blob pool entry", "id", id, "err", err)
return err
}
meta := newBlobTxMeta(id, size, item.Tx)
if tx.BlobTxSidecar() == nil {
log.Error("Missing sidecar in blob pool entry", "id", id, "hash", tx.Hash())
return errors.New("missing blob sidecar")
}
sender, err := p.signer.Sender(item.Tx)
meta := newBlobTxMeta(id, size, tx)
sender, err := p.signer.Sender(tx)
if err != nil {
// This path is impossible unless the signature validity changes across
// restarts. For that ever unprobable case, recover gracefully by ignoring
// this data entry.
log.Error("Failed to recover blob tx sender", "id", id, "hash", item.Tx.Hash(), "err", err)
log.Error("Failed to recover blob tx sender", "id", id, "hash", tx.Hash(), "err", err)
return err
}
if _, ok := p.index[sender]; !ok {
@ -718,17 +713,17 @@ func (p *BlobPool) offload(addr common.Address, nonce uint64, id uint64, inclusi
log.Error("Blobs missing for included transaction", "from", addr, "nonce", nonce, "id", id, "err", err)
return
}
item := new(blobTx)
if err = rlp.DecodeBytes(data, item); err != nil {
var tx types.Transaction
if err = rlp.DecodeBytes(data, tx); err != nil {
log.Error("Blobs corrupted for included transaction", "from", addr, "nonce", nonce, "id", id, "err", err)
return
}
block, ok := inclusions[item.Tx.Hash()]
block, ok := inclusions[tx.Hash()]
if !ok {
log.Warn("Blob transaction swapped out by signer", "from", addr, "nonce", nonce, "id", id)
return
}
if err := p.limbo.push(item.Tx.Hash(), block, item.Blobs, item.Commits, item.Proofs); err != nil {
if err := p.limbo.push(&tx, block); err != nil {
log.Warn("Failed to offload blob tx into limbo", "err", err)
return
}
@ -760,7 +755,7 @@ func (p *BlobPool) Reset(oldHead, newHead *types.Header) {
for addr, txs := range reinject {
// Blindly push all the lost transactions back into the pool
for _, tx := range txs {
p.reinject(addr, tx)
p.reinject(addr, tx.Hash())
}
// Recheck the account's pooled transactions to drop included and
// invalidated one
@ -920,16 +915,19 @@ func (p *BlobPool) reorg(oldHead, newHead *types.Header) (map[common.Address][]*
// Note, the method will not initialize the eviction cache values as those will
// be done once for all transactions belonging to an account after all individual
// transactions are injected back into the pool.
func (p *BlobPool) reinject(addr common.Address, tx *types.Transaction) {
func (p *BlobPool) reinject(addr common.Address, txhash common.Hash) {
// Retrieve the associated blob from the limbo. Without the blobs, we cannot
// add the transaction back into the pool as it is not mineable.
blobs, commits, proofs, err := p.limbo.pull(tx.Hash())
tx, err := p.limbo.pull(txhash)
if err != nil {
log.Error("Blobs unavailable, dropping reorged tx", "err", err)
return
}
// Serialize the transaction back into the primary datastore
blob, err := rlp.EncodeToBytes(&blobTx{Tx: tx, Blobs: blobs, Commits: commits, Proofs: proofs})
// TODO: seems like an easy optimization here would be getting the serialized tx
// from limbo instead of re-serializing it here.
// Serialize the transaction back into the primary datastore.
blob, err := rlp.EncodeToBytes(tx)
if err != nil {
log.Error("Failed to encode transaction for storage", "hash", tx.Hash(), "err", err)
return
@ -939,9 +937,9 @@ func (p *BlobPool) reinject(addr common.Address, tx *types.Transaction) {
log.Error("Failed to write transaction into storage", "hash", tx.Hash(), "err", err)
return
}
// Update the indixes and metrics
meta := newBlobTxMeta(id, p.store.Size(id), tx)
if _, ok := p.index[addr]; !ok {
if err := p.reserve(addr, true); err != nil {
log.Warn("Failed to reserve account for blob pool", "tx", tx.Hash(), "from", addr, "err", err)
@ -1023,7 +1021,7 @@ func (p *BlobPool) SetGasTip(tip *big.Int) {
// validateTx checks whether a transaction is valid according to the consensus
// rules and adheres to some heuristic limits of the local node (price and size).
func (p *BlobPool) validateTx(tx *types.Transaction, blobs []kzg4844.Blob, commits []kzg4844.Commitment, proofs []kzg4844.Proof) error {
func (p *BlobPool) validateTx(tx *types.Transaction) error {
// Ensure the transaction adheres to basic pool filters (type, size, tip) and
// consensus rules
baseOpts := &txpool.ValidationOptions{
@ -1032,7 +1030,7 @@ func (p *BlobPool) validateTx(tx *types.Transaction, blobs []kzg4844.Blob, commi
MaxSize: txMaxSize,
MinTip: p.gasTip.ToBig(),
}
if err := txpool.ValidateTransaction(tx, blobs, commits, proofs, p.head, p.signer, baseOpts); err != nil {
if err := txpool.ValidateTransaction(tx, p.head, p.signer, baseOpts); err != nil {
return err
}
// Ensure the transaction adheres to the stateful pool filters (nonce, balance)
@ -1117,7 +1115,7 @@ func (p *BlobPool) Has(hash common.Hash) bool {
}
// Get returns a transaction if it is contained in the pool, or nil otherwise.
func (p *BlobPool) Get(hash common.Hash) *txpool.Transaction {
func (p *BlobPool) Get(hash common.Hash) *types.Transaction {
// Track the amount of time waiting to retrieve a fully resolved blob tx from
// the pool and the amount of time actually spent on pulling the data from disk.
getStart := time.Now()
@ -1139,32 +1137,27 @@ func (p *BlobPool) Get(hash common.Hash) *txpool.Transaction {
log.Error("Tracked blob transaction missing from store", "hash", hash, "id", id, "err", err)
return nil
}
item := new(blobTx)
item := new(types.Transaction)
if err = rlp.DecodeBytes(data, item); err != nil {
log.Error("Blobs corrupted for traced transaction", "hash", hash, "id", id, "err", err)
return nil
}
return &txpool.Transaction{
Tx: item.Tx,
BlobTxBlobs: item.Blobs,
BlobTxCommits: item.Commits,
BlobTxProofs: item.Proofs,
}
return item
}
// Add inserts a set of blob transactions into the pool if they pass validation (both
// consensus validity and pool restictions).
func (p *BlobPool) Add(txs []*txpool.Transaction, local bool, sync bool) []error {
func (p *BlobPool) Add(txs []*types.Transaction, local bool, sync bool) []error {
errs := make([]error, len(txs))
for i, tx := range txs {
errs[i] = p.add(tx.Tx, tx.BlobTxBlobs, tx.BlobTxCommits, tx.BlobTxProofs)
errs[i] = p.add(tx)
}
return errs
}
// Add inserts a new blob transaction into the pool if it passes validation (both
// consensus validity and pool restictions).
func (p *BlobPool) add(tx *types.Transaction, blobs []kzg4844.Blob, commits []kzg4844.Commitment, proofs []kzg4844.Proof) (err error) {
func (p *BlobPool) add(tx *types.Transaction) (err error) {
// The blob pool blocks on adding a transaction. This is because blob txs are
// only even pulled form the network, so this method will act as the overload
// protection for fetches.
@ -1178,7 +1171,7 @@ func (p *BlobPool) add(tx *types.Transaction, blobs []kzg4844.Blob, commits []kz
}(time.Now())
// Ensure the transaction is valid from all perspectives
if err := p.validateTx(tx, blobs, commits, proofs); err != nil {
if err := p.validateTx(tx); err != nil {
log.Trace("Transaction validation failed", "hash", tx.Hash(), "err", err)
return err
}
@ -1203,7 +1196,7 @@ func (p *BlobPool) add(tx *types.Transaction, blobs []kzg4844.Blob, commits []kz
}
// Transaction permitted into the pool from a nonce and cost perspective,
// insert it into the database and update the indices
blob, err := rlp.EncodeToBytes(&blobTx{Tx: tx, Blobs: blobs, Commits: commits, Proofs: proofs})
blob, err := rlp.EncodeToBytes(tx)
if err != nil {
log.Error("Failed to encode transaction for storage", "hash", tx.Hash(), "err", err)
return err

View file

@ -193,8 +193,8 @@ func makeAddressReserver() txpool.AddressReserver {
// with a valid key, only setting the interesting fields from the perspective of
// the blob pool.
func makeTx(nonce uint64, gasTipCap uint64, gasFeeCap uint64, blobFeeCap uint64, key *ecdsa.PrivateKey) *types.Transaction {
tx, _ := types.SignNewTx(key, types.LatestSigner(testChainConfig), makeUnsignedTx(nonce, gasTipCap, gasFeeCap, blobFeeCap))
return tx
blobtx := makeUnsignedTx(nonce, gasTipCap, gasFeeCap, blobFeeCap)
return types.MustSignNewTx(key, types.LatestSigner(testChainConfig), blobtx)
}
// makeUnsignedTx is a utility method to construct a random blob tranasaction
@ -209,6 +209,11 @@ func makeUnsignedTx(nonce uint64, gasTipCap uint64, gasFeeCap uint64, blobFeeCap
BlobFeeCap: uint256.NewInt(blobFeeCap),
BlobHashes: []common.Hash{emptyBlobVHash},
Value: uint256.NewInt(100),
Sidecar: &types.BlobTxSidecar{
Blobs: []kzg4844.Blob{emptyBlob},
Commitments: []kzg4844.Commitment{emptyBlobCommit},
Proofs: []kzg4844.Proof{emptyBlobProof},
},
}
}
@ -341,7 +346,7 @@ func TestOpenDrops(t *testing.T) {
R: new(uint256.Int),
S: new(uint256.Int),
})
blob, _ := rlp.EncodeToBytes(&blobTx{Tx: tx})
blob, _ := rlp.EncodeToBytes(tx)
badsig, _ := store.Put(blob)
// Insert a sequence of transactions with a nonce gap in between to verify
@ -354,7 +359,7 @@ func TestOpenDrops(t *testing.T) {
)
for _, nonce := range []uint64{0, 1, 3, 4, 6, 7} { // first gap at #2, another at #5
tx := makeTx(nonce, 1, 1, 1, gapper)
blob, _ := rlp.EncodeToBytes(&blobTx{Tx: tx})
blob, _ := rlp.EncodeToBytes(tx)
id, _ := store.Put(blob)
if nonce < 2 {
@ -371,7 +376,7 @@ func TestOpenDrops(t *testing.T) {
)
for _, nonce := range []uint64{1, 2, 3} { // first gap at #0, all set dangling
tx := makeTx(nonce, 1, 1, 1, dangler)
blob, _ := rlp.EncodeToBytes(&blobTx{Tx: tx})
blob, _ := rlp.EncodeToBytes(tx)
id, _ := store.Put(blob)
dangling[id] = struct{}{}
@ -384,7 +389,7 @@ func TestOpenDrops(t *testing.T) {
)
for _, nonce := range []uint64{0, 1, 2} { // account nonce at 3, all set filled
tx := makeTx(nonce, 1, 1, 1, filler)
blob, _ := rlp.EncodeToBytes(&blobTx{Tx: tx})
blob, _ := rlp.EncodeToBytes(tx)
id, _ := store.Put(blob)
filled[id] = struct{}{}
@ -397,7 +402,7 @@ func TestOpenDrops(t *testing.T) {
)
for _, nonce := range []uint64{0, 1, 2, 3} { // account nonce at 2, half filled
tx := makeTx(nonce, 1, 1, 1, overlapper)
blob, _ := rlp.EncodeToBytes(&blobTx{Tx: tx})
blob, _ := rlp.EncodeToBytes(tx)
id, _ := store.Put(blob)
if nonce >= 2 {
@ -419,7 +424,7 @@ func TestOpenDrops(t *testing.T) {
} else {
tx = makeTx(uint64(i), 1, 1, 1, underpayer)
}
blob, _ := rlp.EncodeToBytes(&blobTx{Tx: tx})
blob, _ := rlp.EncodeToBytes(tx)
id, _ := store.Put(blob)
underpaid[id] = struct{}{}
@ -438,7 +443,7 @@ func TestOpenDrops(t *testing.T) {
} else {
tx = makeTx(uint64(i), 1, 1, 1, outpricer)
}
blob, _ := rlp.EncodeToBytes(&blobTx{Tx: tx})
blob, _ := rlp.EncodeToBytes(tx)
id, _ := store.Put(blob)
if i < 2 {
@ -460,7 +465,7 @@ func TestOpenDrops(t *testing.T) {
} else {
tx = makeTx(nonce, 1, 1, 1, exceeder)
}
blob, _ := rlp.EncodeToBytes(&blobTx{Tx: tx})
blob, _ := rlp.EncodeToBytes(tx)
id, _ := store.Put(blob)
exceeded[id] = struct{}{}
@ -478,7 +483,7 @@ func TestOpenDrops(t *testing.T) {
} else {
tx = makeTx(nonce, 1, 1, 1, overdrafter)
}
blob, _ := rlp.EncodeToBytes(&blobTx{Tx: tx})
blob, _ := rlp.EncodeToBytes(tx)
id, _ := store.Put(blob)
if nonce < 1 {
@ -494,7 +499,7 @@ func TestOpenDrops(t *testing.T) {
overcapped = make(map[uint64]struct{})
)
for nonce := uint64(0); nonce < maxTxsPerAccount+3; nonce++ {
blob, _ := rlp.EncodeToBytes(&blobTx{Tx: makeTx(nonce, 1, 1, 1, overcapper)})
blob, _ := rlp.EncodeToBytes(makeTx(nonce, 1, 1, 1, overcapper))
id, _ := store.Put(blob)
if nonce < maxTxsPerAccount {
@ -625,7 +630,7 @@ func TestOpenIndex(t *testing.T) {
)
for _, i := range []int{5, 3, 4, 2, 0, 1} { // Randomize the tx insertion order to force sorting on load
tx := makeTx(uint64(i), txExecTipCaps[i], txExecFeeCaps[i], txBlobFeeCaps[i], key)
blob, _ := rlp.EncodeToBytes(&blobTx{Tx: tx})
blob, _ := rlp.EncodeToBytes(tx)
store.Put(blob)
}
store.Close()
@ -718,9 +723,9 @@ func TestOpenHeap(t *testing.T) {
tx2 = makeTx(0, 1, 800, 70, key2)
tx3 = makeTx(0, 1, 1500, 110, key3)
blob1, _ = rlp.EncodeToBytes(&blobTx{Tx: tx1})
blob2, _ = rlp.EncodeToBytes(&blobTx{Tx: tx2})
blob3, _ = rlp.EncodeToBytes(&blobTx{Tx: tx3})
blob1, _ = rlp.EncodeToBytes(tx1)
blob2, _ = rlp.EncodeToBytes(tx2)
blob3, _ = rlp.EncodeToBytes(tx3)
heapOrder = []common.Address{addr2, addr1, addr3}
heapIndex = map[common.Address]int{addr2: 0, addr1: 1, addr3: 2}
@ -794,9 +799,9 @@ func TestOpenCap(t *testing.T) {
tx2 = makeTx(0, 1, 800, 70, key2)
tx3 = makeTx(0, 1, 1500, 110, key3)
blob1, _ = rlp.EncodeToBytes(&blobTx{Tx: tx1, Blobs: []kzg4844.Blob{emptyBlob}, Commits: []kzg4844.Commitment{emptyBlobCommit}, Proofs: []kzg4844.Proof{emptyBlobProof}})
blob2, _ = rlp.EncodeToBytes(&blobTx{Tx: tx2, Blobs: []kzg4844.Blob{emptyBlob}, Commits: []kzg4844.Commitment{emptyBlobCommit}, Proofs: []kzg4844.Proof{emptyBlobProof}})
blob3, _ = rlp.EncodeToBytes(&blobTx{Tx: tx3, Blobs: []kzg4844.Blob{emptyBlob}, Commits: []kzg4844.Commitment{emptyBlobCommit}, Proofs: []kzg4844.Proof{emptyBlobProof}})
blob1, _ = rlp.EncodeToBytes(tx1)
blob2, _ = rlp.EncodeToBytes(tx2)
blob3, _ = rlp.EncodeToBytes(tx3)
keep = []common.Address{addr1, addr3}
drop = []common.Address{addr2}
@ -1210,10 +1215,8 @@ func TestAdd(t *testing.T) {
// Sign the seed transactions and store them in the data store
for _, tx := range seed.txs {
var (
signed, _ = types.SignNewTx(keys[acc], types.LatestSigner(testChainConfig), tx)
blob, _ = rlp.EncodeToBytes(&blobTx{Tx: signed, Blobs: []kzg4844.Blob{emptyBlob}, Commits: []kzg4844.Commitment{emptyBlobCommit}, Proofs: []kzg4844.Proof{emptyBlobProof}})
)
signed := types.MustSignNewTx(keys[acc], types.LatestSigner(testChainConfig), tx)
blob, _ := rlp.EncodeToBytes(signed)
store.Put(blob)
}
}
@ -1236,7 +1239,7 @@ func TestAdd(t *testing.T) {
// Add each transaction one by one, verifying the pool internals in between
for j, add := range tt.adds {
signed, _ := types.SignNewTx(keys[add.from], types.LatestSigner(testChainConfig), add.tx)
if err := pool.add(signed, []kzg4844.Blob{emptyBlob}, []kzg4844.Commitment{emptyBlobCommit}, []kzg4844.Proof{emptyBlobProof}); !errors.Is(err, add.err) {
if err := pool.add(signed); !errors.Is(err, add.err) {
t.Errorf("test %d, tx %d: adding transaction error mismatch: have %v, want %v", i, j, err, add.err)
}
verifyPoolInternals(t, pool)

View file

@ -21,7 +21,6 @@ import (
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/core/types"
"github.com/ethereum/go-ethereum/crypto/kzg4844"
"github.com/ethereum/go-ethereum/log"
"github.com/ethereum/go-ethereum/rlp"
"github.com/holiman/billy"
@ -31,12 +30,9 @@ import (
// to which it belongs as well as the block number in which it was included for
// finality eviction.
type limboBlob struct {
Owner common.Hash // Owner transaction's hash to support resurrecting reorged txs
Block uint64 // Block in which the blob transaction was included
Blobs []kzg4844.Blob // The opaque blobs originally part of the transaction
Commits []kzg4844.Commitment // The commitments for the original blobs
Proofs []kzg4844.Proof // The proofs verifying the commitments
TxHash common.Hash // Owner transaction's hash to support resurrecting reorged txs
Block uint64 // Block in which the blob transaction was included
Tx *types.Transaction
}
// limbo is a light, indexed database to temporarily store recently included
@ -98,19 +94,19 @@ func (l *limbo) parseBlob(id uint64, data []byte) error {
log.Error("Failed to decode blob limbo entry", "id", id, "err", err)
return err
}
if _, ok := l.index[item.Owner]; ok {
if _, ok := l.index[item.TxHash]; ok {
// This path is impossible, unless due to a programming error a blob gets
// inserted into the limbo which was already part of if. Recover gracefully
// by ignoring this data entry.
log.Error("Dropping duplicate blob limbo entry", "owner", item.Owner, "id", id)
log.Error("Dropping duplicate blob limbo entry", "owner", item.TxHash, "id", id)
return errors.New("duplicate blob")
}
l.index[item.Owner] = id
l.index[item.TxHash] = id
if _, ok := l.groups[item.Block]; !ok {
l.groups[item.Block] = make(map[uint64]common.Hash)
}
l.groups[item.Block][id] = item.Owner
l.groups[item.Block][id] = item.TxHash
return nil
}
@ -139,14 +135,14 @@ func (l *limbo) finalize(final *types.Header) {
// push stores a new blob transaction into the limbo, waiting until finality for
// it to be automatically evicted.
func (l *limbo) push(tx common.Hash, block uint64, blobs []kzg4844.Blob, commits []kzg4844.Commitment, proofs []kzg4844.Proof) error {
func (l *limbo) push(tx *types.Transaction, block uint64) error {
// If the blobs are already tracked by the limbo, consider it a programming
// error. There's not much to do against it, but be loud.
if _, ok := l.index[tx]; ok {
if _, ok := l.index[tx.Hash()]; ok {
log.Error("Limbo cannot push already tracked blobs", "tx", tx)
return errors.New("already tracked blob transaction")
}
if err := l.setAndIndex(tx, block, blobs, commits, proofs); err != nil {
if err := l.setAndIndex(tx, block); err != nil {
log.Error("Failed to set and index liboed blobs", "tx", tx, "err", err)
return err
}
@ -156,21 +152,21 @@ func (l *limbo) push(tx common.Hash, block uint64, blobs []kzg4844.Blob, commits
// pull retrieves a previously pushed set of blobs back from the limbo, removing
// it at the same time. This method should be used when a previously included blob
// transaction gets reorged out.
func (l *limbo) pull(tx common.Hash) ([]kzg4844.Blob, []kzg4844.Commitment, []kzg4844.Proof, error) {
func (l *limbo) pull(tx common.Hash) (*types.Transaction, error) {
// If the blobs are not tracked by the limbo, there's not much to do. This
// can happen for example if a blob transaction is mined without pushing it
// into the network first.
id, ok := l.index[tx]
if !ok {
log.Trace("Limbo cannot pull non-tracked blobs", "tx", tx)
return nil, nil, nil, errors.New("unseen blob transaction")
return nil, errors.New("unseen blob transaction")
}
item, err := l.getAndDrop(id)
if err != nil {
log.Error("Failed to get and drop limboed blobs", "tx", tx, "id", id, "err", err)
return nil, nil, nil, err
return nil, err
}
return item.Blobs, item.Commits, item.Proofs, nil
return item.Tx, nil
}
// update changes the block number under which a blob transaction is tracked. This
@ -180,33 +176,33 @@ func (l *limbo) pull(tx common.Hash) ([]kzg4844.Blob, []kzg4844.Commitment, []kz
// any of it since there's no clear error case. Some errors may be due to coding
// issues, others caused by signers mining MEV stuff or swapping transactions. In
// all cases, the pool needs to continue operating.
func (l *limbo) update(tx common.Hash, block uint64) {
func (l *limbo) update(txhash common.Hash, block uint64) {
// If the blobs are not tracked by the limbo, there's not much to do. This
// can happen for example if a blob transaction is mined without pushing it
// into the network first.
id, ok := l.index[tx]
id, ok := l.index[txhash]
if !ok {
log.Trace("Limbo cannot update non-tracked blobs", "tx", tx)
log.Trace("Limbo cannot update non-tracked blobs", "tx", txhash)
return
}
// If there was no change in the blob's inclusion block, don't mess around
// with heavy database operations.
if _, ok := l.groups[block][id]; ok {
log.Trace("Blob transaction unchanged in limbo", "tx", tx, "block", block)
log.Trace("Blob transaction unchanged in limbo", "tx", txhash, "block", block)
return
}
// Retrieve the old blobs from the data store and write tehm back with a new
// block number. IF anything fails, there's not much to do, go on.
item, err := l.getAndDrop(id)
if err != nil {
log.Error("Failed to get and drop limboed blobs", "tx", tx, "id", id, "err", err)
log.Error("Failed to get and drop limboed blobs", "tx", txhash, "id", id, "err", err)
return
}
if err := l.setAndIndex(tx, block, item.Blobs, item.Commits, item.Proofs); err != nil {
log.Error("Failed to set and index limboed blobs", "tx", tx, "err", err)
if err := l.setAndIndex(item.Tx, block); err != nil {
log.Error("Failed to set and index limboed blobs", "tx", txhash, "err", err)
return
}
log.Trace("Blob transaction updated in limbo", "tx", tx, "old-block", item.Block, "new-block", block)
log.Trace("Blob transaction updated in limbo", "tx", txhash, "old-block", item.Block, "new-block", block)
}
// getAndDrop retrieves a blob item from the limbo store and deletes it both from
@ -220,7 +216,7 @@ func (l *limbo) getAndDrop(id uint64) (*limboBlob, error) {
if err = rlp.DecodeBytes(data, item); err != nil {
return nil, err
}
delete(l.index, item.Owner)
delete(l.index, item.TxHash)
delete(l.groups[item.Block], id)
if len(l.groups[item.Block]) == 0 {
delete(l.groups, item.Block)
@ -233,13 +229,12 @@ func (l *limbo) getAndDrop(id uint64) (*limboBlob, error) {
// setAndIndex assembles a limbo blob database entry and stores it, also updating
// the in-memory indices.
func (l *limbo) setAndIndex(tx common.Hash, block uint64, blobs []kzg4844.Blob, commits []kzg4844.Commitment, proofs []kzg4844.Proof) error {
func (l *limbo) setAndIndex(tx *types.Transaction, block uint64) error {
txhash := tx.Hash()
item := &limboBlob{
Owner: tx,
Block: block,
Blobs: blobs,
Commits: commits,
Proofs: proofs,
TxHash: txhash,
Block: block,
Tx: tx,
}
data, err := rlp.EncodeToBytes(item)
if err != nil {
@ -249,10 +244,10 @@ func (l *limbo) setAndIndex(tx common.Hash, block uint64, blobs []kzg4844.Blob,
if err != nil {
return err
}
l.index[tx] = id
l.index[txhash] = id
if _, ok := l.groups[block]; !ok {
l.groups[block] = make(map[uint64]common.Hash)
}
l.groups[block][id] = tx
l.groups[block][id] = txhash
return nil
}

View file

@ -35,15 +35,15 @@ var (
// The below metrics track the per-shelf metrics for the primary blob store
// and the temporary limbo store.
shelfDatausedGaugeName = "blobpool/shelf-%d/dataused"
shelfDatagapsGaugeName = "blobpool/shelf-%d/datagaps"
shelfSlotusedGaugeName = "blobpool/shelf-%d/slotused"
shelfSlotgapsGaugeName = "blobpool/shelf-%d/slotgaps"
shelfDatausedGaugeName = "blobpool/shelf_%d/dataused"
shelfDatagapsGaugeName = "blobpool/shelf_%d/datagaps"
shelfSlotusedGaugeName = "blobpool/shelf_%d/slotused"
shelfSlotgapsGaugeName = "blobpool/shelf_%d/slotgaps"
limboShelfDatausedGaugeName = "blobpool/limbo/shelf-%d/dataused"
limboShelfDatagapsGaugeName = "blobpool/limbo/shelf-%d/datagaps"
limboShelfSlotusedGaugeName = "blobpool/limbo/shelf-%d/slotused"
limboShelfSlotgapsGaugeName = "blobpool/limbo/shelf-%d/slotgaps"
limboShelfDatausedGaugeName = "blobpool/limbo/shelf_%d/dataused"
limboShelfDatagapsGaugeName = "blobpool/limbo/shelf_%d/datagaps"
limboShelfSlotusedGaugeName = "blobpool/limbo/shelf_%d/slotused"
limboShelfSlotgapsGaugeName = "blobpool/limbo/shelf_%d/slotgaps"
// The oversized metrics aggregate the shelf stats above the max blob count
// limits to track transactions that are just huge, but don't contain blobs.

View file

@ -535,7 +535,7 @@ func (pool *LegacyPool) Pending(enforceTips bool) map[common.Address][]*txpool.L
lazies[i] = &txpool.LazyTransaction{
Pool: pool,
Hash: txs[i].Hash(),
Tx: &txpool.Transaction{Tx: txs[i]},
Tx: txs[i],
Time: txs[i].Time(),
GasFeeCap: txs[i].GasFeeCap(),
GasTipCap: txs[i].GasTipCap(),
@ -588,7 +588,7 @@ func (pool *LegacyPool) validateTxBasics(tx *types.Transaction, local bool) erro
if local {
opts.MinTip = new(big.Int)
}
if err := txpool.ValidateTransaction(tx, nil, nil, nil, pool.currentHead.Load(), pool.signer, opts); err != nil {
if err := txpool.ValidateTransaction(tx, pool.currentHead.Load(), pool.signer, opts); err != nil {
return err
}
return nil
@ -900,26 +900,13 @@ func (pool *LegacyPool) promoteTx(addr common.Address, hash common.Hash, tx *typ
return true
}
// Add enqueues a batch of transactions into the pool if they are valid. Depending
// on the local flag, full pricing contraints will or will not be applied.
//
// If sync is set, the method will block until all internal maintenance related
// to the add is finished. Only use this during tests for determinism!
func (pool *LegacyPool) Add(txs []*txpool.Transaction, local bool, sync bool) []error {
unwrapped := make([]*types.Transaction, len(txs))
for i, tx := range txs {
unwrapped[i] = tx.Tx
}
return pool.addTxs(unwrapped, local, sync)
}
// addLocals enqueues a batch of transactions into the pool if they are valid, marking the
// senders as a local ones, ensuring they go around the local pricing constraints.
//
// This method is used to add transactions from the RPC API and performs synchronous pool
// reorganization and event propagation.
func (pool *LegacyPool) addLocals(txs []*types.Transaction) []error {
return pool.addTxs(txs, !pool.config.NoLocals, true)
return pool.Add(txs, !pool.config.NoLocals, true)
}
// addLocal enqueues a single local transaction into the pool if it is valid. This is
@ -935,7 +922,7 @@ func (pool *LegacyPool) addLocal(tx *types.Transaction) error {
// This method is used to add transactions from the p2p network and does not wait for pool
// reorganization and internal event propagation.
func (pool *LegacyPool) addRemotes(txs []*types.Transaction) []error {
return pool.addTxs(txs, false, false)
return pool.Add(txs, false, false)
}
// addRemote enqueues a single transaction into the pool if it is valid. This is a convenience
@ -947,16 +934,20 @@ func (pool *LegacyPool) addRemote(tx *types.Transaction) error {
// addRemotesSync is like addRemotes, but waits for pool reorganization. Tests use this method.
func (pool *LegacyPool) addRemotesSync(txs []*types.Transaction) []error {
return pool.addTxs(txs, false, true)
return pool.Add(txs, false, true)
}
// This is like addRemotes with a single transaction, but waits for pool reorganization. Tests use this method.
func (pool *LegacyPool) addRemoteSync(tx *types.Transaction) error {
return pool.addTxs([]*types.Transaction{tx}, false, true)[0]
return pool.Add([]*types.Transaction{tx}, false, true)[0]
}
// addTxs attempts to queue a batch of transactions if they are valid.
func (pool *LegacyPool) addTxs(txs []*types.Transaction, local, sync bool) []error {
// Add enqueues a batch of transactions into the pool if they are valid. Depending
// on the local flag, full pricing contraints will or will not be applied.
//
// If sync is set, the method will block until all internal maintenance related
// to the add is finished. Only use this during tests for determinism!
func (pool *LegacyPool) Add(txs []*types.Transaction, local, sync bool) []error {
// Filter out known ones without obtaining the pool lock or recovering signatures
var (
errs = make([]error, len(txs))
@ -1042,12 +1033,12 @@ func (pool *LegacyPool) Status(hash common.Hash) txpool.TxStatus {
}
// Get returns a transaction if it is contained in the pool and nil otherwise.
func (pool *LegacyPool) Get(hash common.Hash) *txpool.Transaction {
func (pool *LegacyPool) Get(hash common.Hash) *types.Transaction {
tx := pool.get(hash)
if tx == nil {
return nil
}
return &txpool.Transaction{Tx: tx}
return tx
}
// get returns a transaction if it is contained in the pool and nil otherwise.

View file

@ -23,27 +23,16 @@ import (
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/core"
"github.com/ethereum/go-ethereum/core/types"
"github.com/ethereum/go-ethereum/crypto/kzg4844"
"github.com/ethereum/go-ethereum/event"
)
// Transaction is a helper struct to group together a canonical transaction with
// satellite data items that are needed by the pool but are not part of the chain.
type Transaction struct {
Tx *types.Transaction // Canonical transaction
BlobTxBlobs []kzg4844.Blob // Blobs needed by the blob pool
BlobTxCommits []kzg4844.Commitment // Commitments needed by the blob pool
BlobTxProofs []kzg4844.Proof // Proofs needed by the blob pool
}
// LazyTransaction contains a small subset of the transaction properties that is
// enough for the miner and other APIs to handle large batches of transactions;
// and supports pulling up the entire transaction when really needed.
type LazyTransaction struct {
Pool SubPool // Transaction subpool to pull the real transaction up
Hash common.Hash // Transaction hash to pull up if needed
Tx *Transaction // Transaction if already resolved
Pool SubPool // Transaction subpool to pull the real transaction up
Hash common.Hash // Transaction hash to pull up if needed
Tx *types.Transaction // Transaction if already resolved
Time time.Time // Time when the transaction was first seen
GasFeeCap *big.Int // Maximum fee per gas the transaction may consume
@ -52,7 +41,7 @@ type LazyTransaction struct {
// Resolve retrieves the full transaction belonging to a lazy handle if it is still
// maintained by the transaction pool.
func (ltx *LazyTransaction) Resolve() *Transaction {
func (ltx *LazyTransaction) Resolve() *types.Transaction {
if ltx.Tx == nil {
ltx.Tx = ltx.Pool.Get(ltx.Hash)
}
@ -99,12 +88,12 @@ type SubPool interface {
Has(hash common.Hash) bool
// Get returns a transaction if it is contained in the pool, or nil otherwise.
Get(hash common.Hash) *Transaction
Get(hash common.Hash) *types.Transaction
// Add enqueues a batch of transactions into the pool if they are valid. Due
// to the large transaction churn, add may postpone fully integrating the tx
// to a later point to batch multiple ones together.
Add(txs []*Transaction, local bool, sync bool) []error
Add(txs []*types.Transaction, local bool, sync bool) []error
// Pending retrieves all currently processable transactions, grouped by origin
// account and sorted by nonce.

View file

@ -249,7 +249,7 @@ func (p *TxPool) Has(hash common.Hash) bool {
}
// Get returns a transaction if it is contained in the pool, or nil otherwise.
func (p *TxPool) Get(hash common.Hash) *Transaction {
func (p *TxPool) Get(hash common.Hash) *types.Transaction {
for _, subpool := range p.subpools {
if tx := subpool.Get(hash); tx != nil {
return tx
@ -261,14 +261,14 @@ func (p *TxPool) Get(hash common.Hash) *Transaction {
// Add enqueues a batch of transactions into the pool if they are valid. Due
// to the large transaction churn, add may postpone fully integrating the tx
// to a later point to batch multiple ones together.
func (p *TxPool) Add(txs []*Transaction, local bool, sync bool) []error {
func (p *TxPool) Add(txs []*types.Transaction, local bool, sync bool) []error {
// Split the input transactions between the subpools. It shouldn't really
// happen that we receive merged batches, but better graceful than strange
// errors.
//
// We also need to track how the transactions were split across the subpools,
// so we can piece back the returned errors into the original order.
txsets := make([][]*Transaction, len(p.subpools))
txsets := make([][]*types.Transaction, len(p.subpools))
splits := make([]int, len(txs))
for i, tx := range txs {
@ -277,7 +277,7 @@ func (p *TxPool) Add(txs []*Transaction, local bool, sync bool) []error {
// Try to find a subpool that accepts the transaction
for j, subpool := range p.subpools {
if subpool.Filter(tx.Tx) {
if subpool.Filter(tx) {
txsets[j] = append(txsets[j], tx)
splits[i] = j
break

View file

@ -46,7 +46,7 @@ type ValidationOptions struct {
//
// This check is public to allow different transaction pools to check the basic
// rules without duplicating code and running the risk of missed updates.
func ValidateTransaction(tx *types.Transaction, blobs []kzg4844.Blob, commits []kzg4844.Commitment, proofs []kzg4844.Proof, head *types.Header, signer types.Signer, opts *ValidationOptions) error {
func ValidateTransaction(tx *types.Transaction, head *types.Header, signer types.Signer, opts *ValidationOptions) error {
// Ensure transactions not implemented by the calling pool are rejected
if opts.Accept&(1<<tx.Type()) == 0 {
return fmt.Errorf("%w: tx type %v not supported by this pool", core.ErrTxTypeNotSupported, tx.Type())
@ -110,6 +110,10 @@ func ValidateTransaction(tx *types.Transaction, blobs []kzg4844.Blob, commits []
}
// Ensure blob transactions have valid commitments
if tx.Type() == types.BlobTxType {
sidecar := tx.BlobTxSidecar()
if sidecar == nil {
return fmt.Errorf("missing sidecar in blob transaction")
}
// Ensure the number of items in the blob transaction and vairous side
// data match up before doing any expensive validations
hashes := tx.BlobHashes()
@ -119,37 +123,44 @@ func ValidateTransaction(tx *types.Transaction, blobs []kzg4844.Blob, commits []
if len(hashes) > params.BlobTxMaxBlobGasPerBlock/params.BlobTxBlobGasPerBlob {
return fmt.Errorf("too many blobs in transaction: have %d, permitted %d", len(hashes), params.BlobTxMaxBlobGasPerBlock/params.BlobTxBlobGasPerBlob)
}
if len(blobs) != len(hashes) {
return fmt.Errorf("invalid number of %d blobs compared to %d blob hashes", len(blobs), len(hashes))
if err := validateBlobSidecar(hashes, sidecar); err != nil {
return err
}
if len(commits) != len(hashes) {
return fmt.Errorf("invalid number of %d blob commitments compared to %d blob hashes", len(commits), len(hashes))
}
if len(proofs) != len(hashes) {
return fmt.Errorf("invalid number of %d blob proofs compared to %d blob hashes", len(proofs), len(hashes))
}
// Blob quantities match up, validate that the provers match with the
// transaction hash before getting to the cryptography
hasher := sha256.New()
for i, want := range hashes {
hasher.Write(commits[i][:])
hash := hasher.Sum(nil)
hasher.Reset()
}
return nil
}
var vhash common.Hash
vhash[0] = params.BlobTxHashVersion
copy(vhash[1:], hash[1:])
func validateBlobSidecar(hashes []common.Hash, sidecar *types.BlobTxSidecar) error {
if len(sidecar.Blobs) != len(hashes) {
return fmt.Errorf("invalid number of %d blobs compared to %d blob hashes", len(sidecar.Blobs), len(hashes))
}
if len(sidecar.Commitments) != len(hashes) {
return fmt.Errorf("invalid number of %d blob commitments compared to %d blob hashes", len(sidecar.Commitments), len(hashes))
}
if len(sidecar.Proofs) != len(hashes) {
return fmt.Errorf("invalid number of %d blob proofs compared to %d blob hashes", len(sidecar.Proofs), len(hashes))
}
// Blob quantities match up, validate that the provers match with the
// transaction hash before getting to the cryptography
hasher := sha256.New()
for i, want := range hashes {
hasher.Write(sidecar.Commitments[i][:])
hash := hasher.Sum(nil)
hasher.Reset()
if vhash != want {
return fmt.Errorf("blob %d: computed hash %#x mismatches transaction one %#x", i, vhash, want)
}
var vhash common.Hash
vhash[0] = params.BlobTxHashVersion
copy(vhash[1:], hash[1:])
if vhash != want {
return fmt.Errorf("blob %d: computed hash %#x mismatches transaction one %#x", i, vhash, want)
}
// Blob commitments match with the hashes in the transaction, verify the
// blobs themselves via KZG
for i := range blobs {
if err := kzg4844.VerifyBlobProof(blobs[i], commits[i], proofs[i]); err != nil {
return fmt.Errorf("invalid blob %d: %v", i, err)
}
}
// Blob commitments match with the hashes in the transaction, verify the
// blobs themselves via KZG
for i := range sidecar.Blobs {
if err := kzg4844.VerifyBlobProof(sidecar.Blobs[i], sidecar.Commitments[i], sidecar.Proofs[i]); err != nil {
return fmt.Errorf("invalid blob %d: %v", i, err)
}
}
return nil

View file

@ -82,9 +82,6 @@ type TxData interface {
value() *big.Int
nonce() uint64
to() *common.Address
blobGas() uint64
blobGasFeeCap() *big.Int
blobHashes() []common.Hash
rawSignatureValues() (v, r, s *big.Int)
setSignatureValues(chainID, v, r, s *big.Int)
@ -96,6 +93,9 @@ type TxData interface {
// copy of the computed value, i.e. callers are allowed to mutate the result.
// Method implementations can use 'dst' to store the result.
effectiveGasPrice(dst *big.Int, baseFee *big.Int) *big.Int
encode(*bytes.Buffer) error
decode([]byte) error
}
// EncodeRLP implements rlp.Encoder
@ -116,7 +116,7 @@ func (tx *Transaction) EncodeRLP(w io.Writer) error {
// encodeTyped writes the canonical encoding of a typed transaction to w.
func (tx *Transaction) encodeTyped(w *bytes.Buffer) error {
w.WriteByte(tx.Type())
return rlp.Encode(w, tx.inner)
return tx.inner.encode(w)
}
// MarshalBinary returns the canonical encoding of the transaction.
@ -186,22 +186,19 @@ func (tx *Transaction) decodeTyped(b []byte) (TxData, error) {
if len(b) <= 1 {
return nil, errShortTypedTx
}
var inner TxData
switch b[0] {
case AccessListTxType:
var inner AccessListTx
err := rlp.DecodeBytes(b[1:], &inner)
return &inner, err
inner = new(AccessListTx)
case DynamicFeeTxType:
var inner DynamicFeeTx
err := rlp.DecodeBytes(b[1:], &inner)
return &inner, err
inner = new(DynamicFeeTx)
case BlobTxType:
var inner BlobTx
err := rlp.DecodeBytes(b[1:], &inner)
return &inner, err
inner = new(BlobTx)
default:
return nil, ErrTxTypeNotSupported
}
err := inner.decode(b[1:])
return inner, err
}
// setDecoded sets the inner transaction and size after decoding.
@ -288,15 +285,6 @@ func (tx *Transaction) GasTipCap() *big.Int { return new(big.Int).Set(tx.inner.g
// GasFeeCap returns the fee cap per gas of the transaction.
func (tx *Transaction) GasFeeCap() *big.Int { return new(big.Int).Set(tx.inner.gasFeeCap()) }
// BlobGas returns the blob gas limit of the transaction for blob transactions, 0 otherwise.
func (tx *Transaction) BlobGas() uint64 { return tx.inner.blobGas() }
// BlobGasFeeCap returns the blob gas fee cap per blob gas of the transaction for blob transactions, nil otherwise.
func (tx *Transaction) BlobGasFeeCap() *big.Int { return tx.inner.blobGasFeeCap() }
// BlobHashes returns the hases of the blob commitments for blob transactions, nil otherwise.
func (tx *Transaction) BlobHashes() []common.Hash { return tx.inner.blobHashes() }
// Value returns the ether amount of the transaction.
func (tx *Transaction) Value() *big.Int { return new(big.Int).Set(tx.inner.value()) }
@ -383,14 +371,66 @@ func (tx *Transaction) EffectiveGasTipIntCmp(other *big.Int, baseFee *big.Int) i
return tx.EffectiveGasTipValue(baseFee).Cmp(other)
}
// BlobGas returns the blob gas limit of the transaction for blob transactions, 0 otherwise.
func (tx *Transaction) BlobGas() uint64 {
if blobtx, ok := tx.inner.(*BlobTx); ok {
return blobtx.blobGas()
}
return 0
}
// BlobGasFeeCap returns the blob gas fee cap per blob gas of the transaction for blob transactions, nil otherwise.
func (tx *Transaction) BlobGasFeeCap() *big.Int {
if blobtx, ok := tx.inner.(*BlobTx); ok {
return blobtx.BlobFeeCap.ToBig()
}
return nil
}
// BlobHashes returns the hases of the blob commitments for blob transactions, nil otherwise.
func (tx *Transaction) BlobHashes() []common.Hash {
if blobtx, ok := tx.inner.(*BlobTx); ok {
return blobtx.BlobHashes
}
return nil
}
// BlobTxSidecar returns the sidecar of a blob transaction, nil otherwise.
func (tx *Transaction) BlobTxSidecar() *BlobTxSidecar {
if blobtx, ok := tx.inner.(*BlobTx); ok {
return blobtx.Sidecar
}
return nil
}
// BlobGasFeeCapCmp compares the blob fee cap of two transactions.
func (tx *Transaction) BlobGasFeeCapCmp(other *Transaction) int {
return tx.inner.blobGasFeeCap().Cmp(other.inner.blobGasFeeCap())
return tx.BlobGasFeeCap().Cmp(other.BlobGasFeeCap())
}
// BlobGasFeeCapIntCmp compares the blob fee cap of the transaction against the given blob fee cap.
func (tx *Transaction) BlobGasFeeCapIntCmp(other *big.Int) int {
return tx.inner.blobGasFeeCap().Cmp(other)
return tx.BlobGasFeeCap().Cmp(other)
}
// WithoutBlobTxSidecar returns a copy of tx with the blob sidecar removed.
func (tx *Transaction) WithoutBlobTxSidecar() *Transaction {
blobtx, ok := tx.inner.(*BlobTx)
if !ok {
return tx
}
cpy := &Transaction{
inner: blobtx.withoutSidecar(),
time: tx.time,
}
// Note: tx.size cache not carried over because the sidecar is included in size!
if h := tx.hash.Load(); h != nil {
cpy.hash.Store(h)
}
if f := tx.from.Load(); f != nil {
cpy.from.Store(f)
}
return cpy
}
// SetTime sets the decoding time of a transaction. This is used by tests to set
@ -428,13 +468,24 @@ func (tx *Transaction) Size() uint64 {
if size := tx.size.Load(); size != nil {
return size.(uint64)
}
// Cache miss, encode and cache.
// Note we rely on the assumption that all tx.inner values are RLP-encoded!
c := writeCounter(0)
rlp.Encode(&c, &tx.inner)
size := uint64(c)
if tx.Type() != LegacyTxType {
size += 1 // type byte
// For blob transactions, add the size of the blob content and the outer list of the
// tx + sidecar encoding.
if sc := tx.BlobTxSidecar(); sc != nil {
size += rlp.ListSize(sc.encodedSize())
}
// For typed transactions, the encoding also includes the leading type byte.
if tx.Type() != LegacyTxType {
size += 1
}
tx.size.Store(size)
return size
}

View file

@ -331,11 +331,7 @@ func (s eip2930Signer) Sender(tx *Transaction) (common.Address, error) {
V, R, S := tx.RawSignatureValues()
switch tx.Type() {
case LegacyTxType:
if !tx.Protected() {
return HomesteadSigner{}.Sender(tx)
}
V = new(big.Int).Sub(V, s.chainIdMul)
V.Sub(V, big8)
return s.EIP155Signer.Sender(tx)
case AccessListTxType:
// AL txs are defined to use 0 and 1 as their recovery
// id, add 27 to become equivalent to unprotected Homestead signatures.
@ -372,15 +368,7 @@ func (s eip2930Signer) SignatureValues(tx *Transaction, sig []byte) (R, S, V *bi
func (s eip2930Signer) Hash(tx *Transaction) common.Hash {
switch tx.Type() {
case LegacyTxType:
return rlpHash([]interface{}{
tx.Nonce(),
tx.GasPrice(),
tx.Gas(),
tx.To(),
tx.Value(),
tx.Data(),
s.chainId, uint(0), uint(0),
})
return s.EIP155Signer.Hash(tx)
case AccessListTxType:
return prefixedRlpHash(
tx.Type(),

View file

@ -17,9 +17,11 @@
package types
import (
"bytes"
"math/big"
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/rlp"
)
//go:generate go run github.com/fjl/gencodec -type AccessTuple -out gen_access_tuple.go
@ -94,20 +96,17 @@ func (tx *AccessListTx) copy() TxData {
}
// accessors for innerTx.
func (tx *AccessListTx) txType() byte { return AccessListTxType }
func (tx *AccessListTx) chainID() *big.Int { return tx.ChainID }
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) gasTipCap() *big.Int { return tx.GasPrice }
func (tx *AccessListTx) gasFeeCap() *big.Int { return tx.GasPrice }
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 }
func (tx *AccessListTx) blobGas() uint64 { return 0 }
func (tx *AccessListTx) blobGasFeeCap() *big.Int { return nil }
func (tx *AccessListTx) blobHashes() []common.Hash { return nil }
func (tx *AccessListTx) txType() byte { return AccessListTxType }
func (tx *AccessListTx) chainID() *big.Int { return tx.ChainID }
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) gasTipCap() *big.Int { return tx.GasPrice }
func (tx *AccessListTx) gasFeeCap() *big.Int { return tx.GasPrice }
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 }
func (tx *AccessListTx) effectiveGasPrice(dst *big.Int, baseFee *big.Int) *big.Int {
return dst.Set(tx.GasPrice)
@ -120,3 +119,11 @@ func (tx *AccessListTx) rawSignatureValues() (v, r, s *big.Int) {
func (tx *AccessListTx) setSignatureValues(chainID, v, r, s *big.Int) {
tx.ChainID, tx.V, tx.R, tx.S = chainID, v, r, s
}
func (tx *AccessListTx) encode(b *bytes.Buffer) error {
return rlp.Encode(b, tx)
}
func (tx *AccessListTx) decode(input []byte) error {
return rlp.DecodeBytes(input, tx)
}

View file

@ -17,10 +17,14 @@
package types
import (
"bytes"
"crypto/sha256"
"math/big"
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/crypto/kzg4844"
"github.com/ethereum/go-ethereum/params"
"github.com/ethereum/go-ethereum/rlp"
"github.com/holiman/uint256"
)
@ -38,12 +42,56 @@ type BlobTx struct {
BlobFeeCap *uint256.Int // a.k.a. maxFeePerBlobGas
BlobHashes []common.Hash
// A blob transaction can optionally contain blobs. This field must be set when BlobTx
// is used to create a transaction for sigining.
Sidecar *BlobTxSidecar `rlp:"-"`
// Signature values
V *uint256.Int `json:"v" gencodec:"required"`
R *uint256.Int `json:"r" gencodec:"required"`
S *uint256.Int `json:"s" gencodec:"required"`
}
// BlobTxSidecar contains the blobs of a blob transaction.
type BlobTxSidecar struct {
Blobs []kzg4844.Blob // Blobs needed by the blob pool
Commitments []kzg4844.Commitment // Commitments needed by the blob pool
Proofs []kzg4844.Proof // Proofs needed by the blob pool
}
// BlobHashes computes the blob hashes of the given blobs.
func (sc *BlobTxSidecar) BlobHashes() []common.Hash {
h := make([]common.Hash, len(sc.Commitments))
for i := range sc.Blobs {
h[i] = blobHash(&sc.Commitments[i])
}
return h
}
// encodedSize computes the RLP size of the sidecar elements. This does NOT return the
// encoded size of the BlobTxSidecar, it's just a helper for tx.Size().
func (sc *BlobTxSidecar) encodedSize() uint64 {
var blobs, commitments, proofs uint64
for i := range sc.Blobs {
blobs += rlp.BytesSize(sc.Blobs[i][:])
}
for i := range sc.Commitments {
commitments += rlp.BytesSize(sc.Commitments[i][:])
}
for i := range sc.Proofs {
proofs += rlp.BytesSize(sc.Proofs[i][:])
}
return rlp.ListSize(blobs) + rlp.ListSize(commitments) + rlp.ListSize(proofs)
}
// blobTxWithBlobs is used for encoding of transactions when blobs are present.
type blobTxWithBlobs struct {
BlobTx *BlobTx
Blobs []kzg4844.Blob
Commitments []kzg4844.Commitment
Proofs []kzg4844.Proof
}
// copy creates a deep copy of the transaction data and initializes all fields.
func (tx *BlobTx) copy() TxData {
cpy := &BlobTx{
@ -90,24 +138,29 @@ func (tx *BlobTx) copy() TxData {
if tx.S != nil {
cpy.S.Set(tx.S)
}
if tx.Sidecar != nil {
cpy.Sidecar = &BlobTxSidecar{
Blobs: append([]kzg4844.Blob(nil), tx.Sidecar.Blobs...),
Commitments: append([]kzg4844.Commitment(nil), tx.Sidecar.Commitments...),
Proofs: append([]kzg4844.Proof(nil), tx.Sidecar.Proofs...),
}
}
return cpy
}
// accessors for innerTx.
func (tx *BlobTx) txType() byte { return BlobTxType }
func (tx *BlobTx) chainID() *big.Int { return tx.ChainID.ToBig() }
func (tx *BlobTx) accessList() AccessList { return tx.AccessList }
func (tx *BlobTx) data() []byte { return tx.Data }
func (tx *BlobTx) gas() uint64 { return tx.Gas }
func (tx *BlobTx) gasFeeCap() *big.Int { return tx.GasFeeCap.ToBig() }
func (tx *BlobTx) gasTipCap() *big.Int { return tx.GasTipCap.ToBig() }
func (tx *BlobTx) gasPrice() *big.Int { return tx.GasFeeCap.ToBig() }
func (tx *BlobTx) value() *big.Int { return tx.Value.ToBig() }
func (tx *BlobTx) nonce() uint64 { return tx.Nonce }
func (tx *BlobTx) to() *common.Address { tmp := tx.To; return &tmp }
func (tx *BlobTx) blobGas() uint64 { return params.BlobTxBlobGasPerBlob * uint64(len(tx.BlobHashes)) }
func (tx *BlobTx) blobGasFeeCap() *big.Int { return tx.BlobFeeCap.ToBig() }
func (tx *BlobTx) blobHashes() []common.Hash { return tx.BlobHashes }
func (tx *BlobTx) txType() byte { return BlobTxType }
func (tx *BlobTx) chainID() *big.Int { return tx.ChainID.ToBig() }
func (tx *BlobTx) accessList() AccessList { return tx.AccessList }
func (tx *BlobTx) data() []byte { return tx.Data }
func (tx *BlobTx) gas() uint64 { return tx.Gas }
func (tx *BlobTx) gasFeeCap() *big.Int { return tx.GasFeeCap.ToBig() }
func (tx *BlobTx) gasTipCap() *big.Int { return tx.GasTipCap.ToBig() }
func (tx *BlobTx) gasPrice() *big.Int { return tx.GasFeeCap.ToBig() }
func (tx *BlobTx) value() *big.Int { return tx.Value.ToBig() }
func (tx *BlobTx) nonce() uint64 { return tx.Nonce }
func (tx *BlobTx) to() *common.Address { tmp := tx.To; return &tmp }
func (tx *BlobTx) blobGas() uint64 { return params.BlobTxBlobGasPerBlob * uint64(len(tx.BlobHashes)) }
func (tx *BlobTx) effectiveGasPrice(dst *big.Int, baseFee *big.Int) *big.Int {
if baseFee == nil {
@ -130,3 +183,64 @@ func (tx *BlobTx) setSignatureValues(chainID, v, r, s *big.Int) {
tx.R.SetFromBig(r)
tx.S.SetFromBig(s)
}
func (tx *BlobTx) withoutSidecar() *BlobTx {
cpy := *tx
cpy.Sidecar = nil
return &cpy
}
func (tx *BlobTx) encode(b *bytes.Buffer) error {
if tx.Sidecar == nil {
return rlp.Encode(b, tx)
}
inner := &blobTxWithBlobs{
BlobTx: tx,
Blobs: tx.Sidecar.Blobs,
Commitments: tx.Sidecar.Commitments,
Proofs: tx.Sidecar.Proofs,
}
return rlp.Encode(b, inner)
}
func (tx *BlobTx) decode(input []byte) error {
// Here we need to support two formats: the network protocol encoding of the tx (with
// blobs) or the canonical encoding without blobs.
//
// The two encodings can be distinguished by checking whether the first element of the
// input list is itself a list.
outerList, _, err := rlp.SplitList(input)
if err != nil {
return err
}
firstElemKind, _, _, err := rlp.Split(outerList)
if err != nil {
return err
}
if firstElemKind != rlp.List {
return rlp.DecodeBytes(input, tx)
}
// It's a tx with blobs.
var inner blobTxWithBlobs
if err := rlp.DecodeBytes(input, &inner); err != nil {
return err
}
*tx = *inner.BlobTx
tx.Sidecar = &BlobTxSidecar{
Blobs: inner.Blobs,
Commitments: inner.Commitments,
Proofs: inner.Proofs,
}
return nil
}
func blobHash(commit *kzg4844.Commitment) common.Hash {
hasher := sha256.New()
hasher.Write(commit[:])
var vhash common.Hash
hasher.Sum(vhash[:0])
vhash[0] = params.BlobTxHashVersion
return vhash
}

View file

@ -0,0 +1,90 @@
package types
import (
"crypto/ecdsa"
"testing"
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/crypto"
"github.com/ethereum/go-ethereum/crypto/kzg4844"
"github.com/holiman/uint256"
)
// This test verifies that tx.Hash() is not affected by presence of a BlobTxSidecar.
func TestBlobTxHashing(t *testing.T) {
key, _ := crypto.GenerateKey()
withBlobs := createEmptyBlobTx(key, true)
withBlobsStripped := withBlobs.WithoutBlobTxSidecar()
withoutBlobs := createEmptyBlobTx(key, false)
hash := withBlobs.Hash()
t.Log("tx hash:", hash)
if h := withBlobsStripped.Hash(); h != hash {
t.Fatal("wrong tx hash after WithoutBlobTxSidecar:", h)
}
if h := withoutBlobs.Hash(); h != hash {
t.Fatal("wrong tx hash on tx created without sidecar:", h)
}
}
// This test verifies that tx.Size() takes BlobTxSidecar into account.
func TestBlobTxSize(t *testing.T) {
key, _ := crypto.GenerateKey()
withBlobs := createEmptyBlobTx(key, true)
withBlobsStripped := withBlobs.WithoutBlobTxSidecar()
withoutBlobs := createEmptyBlobTx(key, false)
withBlobsEnc, _ := withBlobs.MarshalBinary()
withoutBlobsEnc, _ := withoutBlobs.MarshalBinary()
size := withBlobs.Size()
t.Log("size with blobs:", size)
sizeNoBlobs := withoutBlobs.Size()
t.Log("size without blobs:", sizeNoBlobs)
if size != uint64(len(withBlobsEnc)) {
t.Error("wrong size with blobs:", size, "encoded length:", len(withBlobsEnc))
}
if sizeNoBlobs != uint64(len(withoutBlobsEnc)) {
t.Error("wrong size without blobs:", sizeNoBlobs, "encoded length:", len(withoutBlobsEnc))
}
if sizeNoBlobs >= size {
t.Error("size without blobs >= size with blobs")
}
if sz := withBlobsStripped.Size(); sz != sizeNoBlobs {
t.Fatal("wrong size on tx after WithoutBlobTxSidecar:", sz)
}
}
var (
emptyBlob = kzg4844.Blob{}
emptyBlobCommit, _ = kzg4844.BlobToCommitment(emptyBlob)
emptyBlobProof, _ = kzg4844.ComputeBlobProof(emptyBlob, emptyBlobCommit)
)
func createEmptyBlobTx(key *ecdsa.PrivateKey, withSidecar bool) *Transaction {
sidecar := &BlobTxSidecar{
Blobs: []kzg4844.Blob{emptyBlob},
Commitments: []kzg4844.Commitment{emptyBlobCommit},
Proofs: []kzg4844.Proof{emptyBlobProof},
}
blobtx := &BlobTx{
ChainID: uint256.NewInt(1),
Nonce: 5,
GasTipCap: uint256.NewInt(22),
GasFeeCap: uint256.NewInt(5),
Gas: 25000,
To: common.Address{0x03, 0x04, 0x05},
Value: uint256.NewInt(99),
Data: make([]byte, 50),
BlobFeeCap: uint256.NewInt(15),
BlobHashes: sidecar.BlobHashes(),
}
if withSidecar {
blobtx.Sidecar = sidecar
}
signer := NewCancunSigner(blobtx.ChainID.ToBig())
return MustSignNewTx(key, signer, blobtx)
}

View file

@ -17,9 +17,11 @@
package types
import (
"bytes"
"math/big"
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/rlp"
)
// DynamicFeeTx represents an EIP-1559 transaction.
@ -83,20 +85,17 @@ func (tx *DynamicFeeTx) copy() TxData {
}
// accessors for innerTx.
func (tx *DynamicFeeTx) txType() byte { return DynamicFeeTxType }
func (tx *DynamicFeeTx) chainID() *big.Int { return tx.ChainID }
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) gasTipCap() *big.Int { return tx.GasTipCap }
func (tx *DynamicFeeTx) gasPrice() *big.Int { return tx.GasFeeCap }
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 }
func (tx *DynamicFeeTx) blobGas() uint64 { return 0 }
func (tx *DynamicFeeTx) blobGasFeeCap() *big.Int { return nil }
func (tx *DynamicFeeTx) blobHashes() []common.Hash { return nil }
func (tx *DynamicFeeTx) txType() byte { return DynamicFeeTxType }
func (tx *DynamicFeeTx) chainID() *big.Int { return tx.ChainID }
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) gasTipCap() *big.Int { return tx.GasTipCap }
func (tx *DynamicFeeTx) gasPrice() *big.Int { return tx.GasFeeCap }
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 }
func (tx *DynamicFeeTx) effectiveGasPrice(dst *big.Int, baseFee *big.Int) *big.Int {
if baseFee == nil {
@ -116,3 +115,11 @@ func (tx *DynamicFeeTx) rawSignatureValues() (v, r, s *big.Int) {
func (tx *DynamicFeeTx) setSignatureValues(chainID, v, r, s *big.Int) {
tx.ChainID, tx.V, tx.R, tx.S = chainID, v, r, s
}
func (tx *DynamicFeeTx) encode(b *bytes.Buffer) error {
return rlp.Encode(b, tx)
}
func (tx *DynamicFeeTx) decode(input []byte) error {
return rlp.DecodeBytes(input, tx)
}

View file

@ -17,6 +17,7 @@
package types
import (
"bytes"
"math/big"
"github.com/ethereum/go-ethereum/common"
@ -91,20 +92,17 @@ func (tx *LegacyTx) copy() TxData {
}
// accessors for innerTx.
func (tx *LegacyTx) txType() byte { return LegacyTxType }
func (tx *LegacyTx) chainID() *big.Int { return deriveChainId(tx.V) }
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) gasTipCap() *big.Int { return tx.GasPrice }
func (tx *LegacyTx) gasFeeCap() *big.Int { return tx.GasPrice }
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 }
func (tx *LegacyTx) blobGas() uint64 { return 0 }
func (tx *LegacyTx) blobGasFeeCap() *big.Int { return nil }
func (tx *LegacyTx) blobHashes() []common.Hash { return nil }
func (tx *LegacyTx) txType() byte { return LegacyTxType }
func (tx *LegacyTx) chainID() *big.Int { return deriveChainId(tx.V) }
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) gasTipCap() *big.Int { return tx.GasPrice }
func (tx *LegacyTx) gasFeeCap() *big.Int { return tx.GasPrice }
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 }
func (tx *LegacyTx) effectiveGasPrice(dst *big.Int, baseFee *big.Int) *big.Int {
return dst.Set(tx.GasPrice)
@ -117,3 +115,11 @@ func (tx *LegacyTx) rawSignatureValues() (v, r, s *big.Int) {
func (tx *LegacyTx) setSignatureValues(chainID, v, r, s *big.Int) {
tx.V, tx.R, tx.S = v, r, s
}
func (tx *LegacyTx) encode(*bytes.Buffer) error {
panic("encode called on LegacyTx")
}
func (tx *LegacyTx) decode([]byte) error {
panic("decode called on LegacyTx)")
}

View file

@ -294,7 +294,7 @@ 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.Add([]*txpool.Transaction{{Tx: signedTx}}, true, false)[0]
return b.eth.txPool.Add([]*types.Transaction{signedTx}, true, false)[0]
}
func (b *EthAPIBackend) GetPoolTransactions() (types.Transactions, error) {
@ -303,7 +303,7 @@ func (b *EthAPIBackend) GetPoolTransactions() (types.Transactions, error) {
for _, batch := range pending {
for _, lazy := range batch {
if tx := lazy.Resolve(); tx != nil {
txs = append(txs, tx.Tx)
txs = append(txs, tx)
}
}
}
@ -311,10 +311,7 @@ func (b *EthAPIBackend) GetPoolTransactions() (types.Transactions, error) {
}
func (b *EthAPIBackend) GetPoolTransaction(hash common.Hash) *types.Transaction {
if tx := b.eth.txPool.Get(hash); tx != nil {
return tx.Tx
}
return nil
return b.eth.txPool.Get(hash)
}
func (b *EthAPIBackend) GetTransaction(ctx context.Context, txHash common.Hash) (*types.Transaction, common.Hash, uint64, uint64, error) {

View file

@ -105,7 +105,7 @@ func TestAccountRange(t *testing.T) {
}
// Test to see if it's possible to recover from the middle of the previous
// set and get an even split between the first and second sets.
slices.SortFunc(hList, common.Hash.Less)
slices.SortFunc(hList, common.Hash.Cmp)
middleH := hList[AccountRangeMaxResults/2]
middleResult := accountRangeTest(t, &trie, sdb, middleH, AccountRangeMaxResults, AccountRangeMaxResults)
missing, infirst, insecond := 0, 0, 0

View file

@ -35,7 +35,6 @@ import (
beaconConsensus "github.com/ethereum/go-ethereum/consensus/beacon"
"github.com/ethereum/go-ethereum/consensus/ethash"
"github.com/ethereum/go-ethereum/core"
"github.com/ethereum/go-ethereum/core/txpool"
"github.com/ethereum/go-ethereum/core/types"
"github.com/ethereum/go-ethereum/crypto"
"github.com/ethereum/go-ethereum/crypto/kzg4844"
@ -108,7 +107,7 @@ func TestEth2AssembleBlock(t *testing.T) {
if err != nil {
t.Fatalf("error signing transaction, err=%v", err)
}
ethservice.TxPool().Add([]*txpool.Transaction{{Tx: tx}}, true, false)
ethservice.TxPool().Add([]*types.Transaction{tx}, true, false)
blockParams := engine.PayloadAttributes{
Timestamp: blocks[9].Time() + 5,
}
@ -145,11 +144,7 @@ func TestEth2AssembleBlockWithAnotherBlocksTxs(t *testing.T) {
// Put the 10th block's tx in the pool and produce a new block
txs := blocks[9].Transactions()
wrapped := make([]*txpool.Transaction, len(txs))
for i, tx := range txs {
wrapped[i] = &txpool.Transaction{Tx: tx}
}
api.eth.TxPool().Add(wrapped, false, true)
api.eth.TxPool().Add(txs, false, true)
blockParams := engine.PayloadAttributes{
Timestamp: blocks[8].Time() + 5,
}
@ -189,11 +184,7 @@ func TestEth2PrepareAndGetPayload(t *testing.T) {
// Put the 10th block's tx in the pool and produce a new block
txs := blocks[9].Transactions()
wrapped := make([]*txpool.Transaction, len(txs))
for i, tx := range txs {
wrapped[i] = &txpool.Transaction{Tx: tx}
}
ethservice.TxPool().Add(wrapped, true, false)
ethservice.TxPool().Add(txs, true, false)
blockParams := engine.PayloadAttributes{
Timestamp: blocks[8].Time() + 5,
}
@ -315,7 +306,7 @@ func TestEth2NewBlock(t *testing.T) {
statedb, _ := ethservice.BlockChain().StateAt(parent.Root())
nonce := statedb.GetNonce(testAddr)
tx, _ := types.SignTx(types.NewContractCreation(nonce, new(big.Int), 1000000, big.NewInt(2*params.InitialBaseFee), logCode), types.LatestSigner(ethservice.BlockChain().Config()), testKey)
ethservice.TxPool().Add([]*txpool.Transaction{{Tx: tx}}, true, false)
ethservice.TxPool().Add([]*types.Transaction{tx}, true, false)
execData, err := assembleWithTransactions(api, parent.Hash(), &engine.PayloadAttributes{
Timestamp: parent.Time() + 5,
@ -484,7 +475,7 @@ func TestFullAPI(t *testing.T) {
statedb, _ := ethservice.BlockChain().StateAt(parent.Root)
nonce := statedb.GetNonce(testAddr)
tx, _ := types.SignTx(types.NewContractCreation(nonce, new(big.Int), 1000000, big.NewInt(2*params.InitialBaseFee), logCode), types.LatestSigner(ethservice.BlockChain().Config()), testKey)
ethservice.TxPool().Add([]*txpool.Transaction{{Tx: tx}}, true, false)
ethservice.TxPool().Add([]*types.Transaction{tx}, true, false)
}
setupBlocks(t, ethservice, 10, parent, callback, nil)
@ -610,7 +601,7 @@ func TestNewPayloadOnInvalidChain(t *testing.T) {
GasPrice: big.NewInt(2 * params.InitialBaseFee),
Data: logCode,
})
ethservice.TxPool().Add([]*txpool.Transaction{{Tx: tx}}, false, true)
ethservice.TxPool().Add([]*types.Transaction{tx}, false, true)
var (
params = engine.PayloadAttributes{
Timestamp: parent.Time + 1,
@ -1284,7 +1275,7 @@ func setupBodies(t *testing.T) (*node.Node, *eth.Ethereum, []*types.Block) {
statedb, _ := ethservice.BlockChain().StateAt(parent.Root)
nonce := statedb.GetNonce(testAddr)
tx, _ := types.SignTx(types.NewContractCreation(nonce, new(big.Int), 1000000, big.NewInt(2*params.InitialBaseFee), logCode), types.LatestSigner(ethservice.BlockChain().Config()), testKey)
ethservice.TxPool().Add([]*txpool.Transaction{{Tx: tx}}, true, false)
ethservice.TxPool().Add([]*types.Transaction{tx}, false, false)
}
withdrawals := make([][]*types.Withdrawal, 10)

View file

@ -798,7 +798,7 @@ func (q *queue) DeliverBodies(id string, txLists [][]*types.Transaction, txListH
}
}
// Blocks must have a number of blobs corresponding to the header gas usage,
// and zero before the Cancun hardfork
// and zero before the Cancun hardfork.
var blobs int
for _, tx := range txLists[index] {
// Count the number of blobs to validate against the header's blobGasUsed
@ -814,6 +814,9 @@ func (q *queue) DeliverBodies(id string, txLists [][]*types.Transaction, txListH
return errInvalidBody
}
}
if tx.BlobTxSidecar() != nil {
return errInvalidBody
}
}
}
if header.BlobGasUsed != nil {

View file

@ -169,9 +169,9 @@ type TxFetcher struct {
alternates map[common.Hash]map[string]struct{} // In-flight transaction alternate origins if retrieval fails
// Callbacks
hasTx func(common.Hash) bool // Retrieves a tx from the local txpool
addTxs func([]*txpool.Transaction) []error // Insert a batch of transactions into local txpool
fetchTxs func(string, []common.Hash) error // Retrieves a set of txs from a remote peer
hasTx func(common.Hash) bool // Retrieves a tx from the local txpool
addTxs func([]*types.Transaction) []error // Insert a batch of transactions into local txpool
fetchTxs func(string, []common.Hash) error // Retrieves a set of txs from a remote peer
step chan struct{} // Notification channel when the fetcher loop iterates
clock mclock.Clock // Time wrapper to simulate in tests
@ -180,14 +180,14 @@ type TxFetcher struct {
// NewTxFetcher creates a transaction fetcher to retrieve transaction
// based on hash announcements.
func NewTxFetcher(hasTx func(common.Hash) bool, addTxs func([]*txpool.Transaction) []error, fetchTxs func(string, []common.Hash) error) *TxFetcher {
func NewTxFetcher(hasTx func(common.Hash) bool, addTxs func([]*types.Transaction) []error, fetchTxs func(string, []common.Hash) error) *TxFetcher {
return NewTxFetcherForTests(hasTx, addTxs, fetchTxs, mclock.System{}, nil)
}
// NewTxFetcherForTests is a testing method to mock out the realtime clock with
// a simulated version and the internal randomness with a deterministic one.
func NewTxFetcherForTests(
hasTx func(common.Hash) bool, addTxs func([]*txpool.Transaction) []error, fetchTxs func(string, []common.Hash) error,
hasTx func(common.Hash) bool, addTxs func([]*types.Transaction) []error, fetchTxs func(string, []common.Hash) error,
clock mclock.Clock, rand *mrand.Rand) *TxFetcher {
return &TxFetcher{
notify: make(chan *txAnnounce),
@ -295,11 +295,7 @@ func (f *TxFetcher) Enqueue(peer string, txs []*types.Transaction, direct bool)
)
batch := txs[i:end]
wrapped := make([]*txpool.Transaction, len(batch))
for j, tx := range batch {
wrapped[j] = &txpool.Transaction{Tx: tx}
}
for j, err := range f.addTxs(wrapped) {
for j, err := range f.addTxs(batch) {
// Track the transaction hash if the price is too low for us.
// Avoid re-request this transaction when we receive another
// announcement.

View file

@ -378,7 +378,7 @@ func TestTransactionFetcherCleanup(t *testing.T) {
init: func() *TxFetcher {
return NewTxFetcher(
func(common.Hash) bool { return false },
func(txs []*txpool.Transaction) []error {
func(txs []*types.Transaction) []error {
return make([]error, len(txs))
},
func(string, []common.Hash) error { return nil },
@ -417,7 +417,7 @@ func TestTransactionFetcherCleanupEmpty(t *testing.T) {
init: func() *TxFetcher {
return NewTxFetcher(
func(common.Hash) bool { return false },
func(txs []*txpool.Transaction) []error {
func(txs []*types.Transaction) []error {
return make([]error, len(txs))
},
func(string, []common.Hash) error { return nil },
@ -455,7 +455,7 @@ func TestTransactionFetcherMissingRescheduling(t *testing.T) {
init: func() *TxFetcher {
return NewTxFetcher(
func(common.Hash) bool { return false },
func(txs []*txpool.Transaction) []error {
func(txs []*types.Transaction) []error {
return make([]error, len(txs))
},
func(string, []common.Hash) error { return nil },
@ -501,7 +501,7 @@ func TestTransactionFetcherMissingCleanup(t *testing.T) {
init: func() *TxFetcher {
return NewTxFetcher(
func(common.Hash) bool { return false },
func(txs []*txpool.Transaction) []error {
func(txs []*types.Transaction) []error {
return make([]error, len(txs))
},
func(string, []common.Hash) error { return nil },
@ -539,7 +539,7 @@ func TestTransactionFetcherBroadcasts(t *testing.T) {
init: func() *TxFetcher {
return NewTxFetcher(
func(common.Hash) bool { return false },
func(txs []*txpool.Transaction) []error {
func(txs []*types.Transaction) []error {
return make([]error, len(txs))
},
func(string, []common.Hash) error { return nil },
@ -644,7 +644,7 @@ func TestTransactionFetcherTimeoutRescheduling(t *testing.T) {
init: func() *TxFetcher {
return NewTxFetcher(
func(common.Hash) bool { return false },
func(txs []*txpool.Transaction) []error {
func(txs []*types.Transaction) []error {
return make([]error, len(txs))
},
func(string, []common.Hash) error { return nil },
@ -865,7 +865,7 @@ func TestTransactionFetcherUnderpricedDedup(t *testing.T) {
init: func() *TxFetcher {
return NewTxFetcher(
func(common.Hash) bool { return false },
func(txs []*txpool.Transaction) []error {
func(txs []*types.Transaction) []error {
errs := make([]error, len(txs))
for i := 0; i < len(errs); i++ {
if i%2 == 0 {
@ -938,7 +938,7 @@ func TestTransactionFetcherUnderpricedDoSProtection(t *testing.T) {
init: func() *TxFetcher {
return NewTxFetcher(
func(common.Hash) bool { return false },
func(txs []*txpool.Transaction) []error {
func(txs []*types.Transaction) []error {
errs := make([]error, len(txs))
for i := 0; i < len(errs); i++ {
errs[i] = txpool.ErrUnderpriced
@ -964,7 +964,7 @@ func TestTransactionFetcherOutOfBoundDeliveries(t *testing.T) {
init: func() *TxFetcher {
return NewTxFetcher(
func(common.Hash) bool { return false },
func(txs []*txpool.Transaction) []error {
func(txs []*types.Transaction) []error {
return make([]error, len(txs))
},
func(string, []common.Hash) error { return nil },
@ -1017,7 +1017,7 @@ func TestTransactionFetcherDrop(t *testing.T) {
init: func() *TxFetcher {
return NewTxFetcher(
func(common.Hash) bool { return false },
func(txs []*txpool.Transaction) []error {
func(txs []*types.Transaction) []error {
return make([]error, len(txs))
},
func(string, []common.Hash) error { return nil },
@ -1083,7 +1083,7 @@ func TestTransactionFetcherDropRescheduling(t *testing.T) {
init: func() *TxFetcher {
return NewTxFetcher(
func(common.Hash) bool { return false },
func(txs []*txpool.Transaction) []error {
func(txs []*types.Transaction) []error {
return make([]error, len(txs))
},
func(string, []common.Hash) error { return nil },
@ -1128,7 +1128,7 @@ func TestTransactionFetcherFuzzCrash01(t *testing.T) {
init: func() *TxFetcher {
return NewTxFetcher(
func(common.Hash) bool { return false },
func(txs []*txpool.Transaction) []error {
func(txs []*types.Transaction) []error {
return make([]error, len(txs))
},
func(string, []common.Hash) error { return nil },
@ -1155,7 +1155,7 @@ func TestTransactionFetcherFuzzCrash02(t *testing.T) {
init: func() *TxFetcher {
return NewTxFetcher(
func(common.Hash) bool { return false },
func(txs []*txpool.Transaction) []error {
func(txs []*types.Transaction) []error {
return make([]error, len(txs))
},
func(string, []common.Hash) error { return nil },
@ -1184,7 +1184,7 @@ func TestTransactionFetcherFuzzCrash03(t *testing.T) {
init: func() *TxFetcher {
return NewTxFetcher(
func(common.Hash) bool { return false },
func(txs []*txpool.Transaction) []error {
func(txs []*types.Transaction) []error {
return make([]error, len(txs))
},
func(string, []common.Hash) error { return nil },
@ -1217,7 +1217,7 @@ func TestTransactionFetcherFuzzCrash04(t *testing.T) {
init: func() *TxFetcher {
return NewTxFetcher(
func(common.Hash) bool { return false },
func(txs []*txpool.Transaction) []error {
func(txs []*types.Transaction) []error {
return make([]error, len(txs))
},
func(string, []common.Hash) error {

View file

@ -111,8 +111,8 @@ func (oracle *Oracle) processBlock(bf *blockFees, percentiles []float64) {
reward, _ := tx.EffectiveGasTip(bf.block.BaseFee())
sorter[i] = txGasAndReward{gasUsed: bf.receipts[i].GasUsed, reward: reward}
}
slices.SortStableFunc(sorter, func(a, b txGasAndReward) bool {
return a.reward.Cmp(b.reward) < 0
slices.SortStableFunc(sorter, func(a, b txGasAndReward) int {
return a.reward.Cmp(b.reward)
})
var txIndex int

View file

@ -208,7 +208,7 @@ func (oracle *Oracle) SuggestTipCap(ctx context.Context) (*big.Int, error) {
}
price := lastPrice
if len(results) > 0 {
slices.SortFunc(results, func(a, b *big.Int) bool { return a.Cmp(b) < 0 })
slices.SortFunc(results, func(a, b *big.Int) int { return a.Cmp(b) })
price = results[(len(results)-1)*oracle.percentile/100]
}
if price.Cmp(oracle.maxPrice) > 0 {
@ -247,12 +247,12 @@ func (oracle *Oracle) getBlockValues(ctx context.Context, blockNum uint64, limit
sortedTxs := make([]*types.Transaction, len(txs))
copy(sortedTxs, txs)
baseFee := block.BaseFee()
slices.SortFunc(sortedTxs, func(a, b *types.Transaction) bool {
slices.SortFunc(sortedTxs, func(a, b *types.Transaction) int {
// It's okay to discard the error because a tx would never be
// accepted into a block with an invalid effective tip.
tip1, _ := a.EffectiveGasTip(baseFee)
tip2, _ := b.EffectiveGasTip(baseFee)
return tip1.Cmp(tip2) < 0
return tip1.Cmp(tip2)
})
var prices []*big.Int

View file

@ -68,10 +68,10 @@ type txPool interface {
// Get retrieves the transaction from local txpool with given
// tx hash.
Get(hash common.Hash) *txpool.Transaction
Get(hash common.Hash) *types.Transaction
// Add should add the given transactions to the pool.
Add(txs []*txpool.Transaction, local bool, sync bool) []error
Add(txs []*types.Transaction, local bool, sync bool) []error
// Pending should return pending transactions.
// The slice should be modifiable by the caller.
@ -287,7 +287,7 @@ func newHandler(config *handlerConfig) (*handler, error) {
}
return p.RequestTxs(hashes)
}
addTxs := func(txs []*txpool.Transaction) []error {
addTxs := func(txs []*types.Transaction) []error {
return h.txpool.Add(txs, false, false)
}
h.txFetcher = fetcher.NewTxFetcher(h.txpool.Has, addTxs, fetchTx)

View file

@ -28,7 +28,6 @@ import (
"github.com/ethereum/go-ethereum/core"
"github.com/ethereum/go-ethereum/core/forkid"
"github.com/ethereum/go-ethereum/core/rawdb"
"github.com/ethereum/go-ethereum/core/txpool"
"github.com/ethereum/go-ethereum/core/types"
"github.com/ethereum/go-ethereum/core/vm"
"github.com/ethereum/go-ethereum/eth/downloader"
@ -308,12 +307,11 @@ func testSendTransactions(t *testing.T, protocol uint) {
handler := newTestHandler()
defer handler.close()
insert := make([]*txpool.Transaction, 100)
insert := make([]*types.Transaction, 100)
for nonce := range insert {
tx := types.NewTransaction(uint64(nonce), common.Address{}, big.NewInt(0), 100000, big.NewInt(0), make([]byte, 10240))
tx, _ = types.SignTx(tx, types.HomesteadSigner{}, testKey)
insert[nonce] = &txpool.Transaction{Tx: tx}
insert[nonce] = tx
}
go handler.txpool.Add(insert, false, false) // Need goroutine to not block on feed
time.Sleep(250 * time.Millisecond) // Wait until tx events get out of the system (can't use events, tx broadcaster races with peer join)
@ -376,8 +374,8 @@ func testSendTransactions(t *testing.T, protocol uint) {
}
}
for _, tx := range insert {
if _, ok := seen[tx.Tx.Hash()]; !ok {
t.Errorf("missing transaction: %x", tx.Tx.Hash())
if _, ok := seen[tx.Hash()]; !ok {
t.Errorf("missing transaction: %x", tx.Hash())
}
}
}
@ -434,12 +432,11 @@ func testTransactionPropagation(t *testing.T, protocol uint) {
defer sub.Unsubscribe()
}
// Fill the source pool with transactions and wait for them at the sinks
txs := make([]*txpool.Transaction, 1024)
txs := make([]*types.Transaction, 1024)
for nonce := range txs {
tx := types.NewTransaction(uint64(nonce), common.Address{}, big.NewInt(0), 100000, big.NewInt(0), nil)
tx, _ = types.SignTx(tx, types.HomesteadSigner{}, testKey)
txs[nonce] = &txpool.Transaction{Tx: tx}
txs[nonce] = tx
}
source.txpool.Add(txs, false, false)

View file

@ -72,32 +72,23 @@ func (p *testTxPool) Has(hash common.Hash) bool {
// Get retrieves the transaction from local txpool with given
// tx hash.
func (p *testTxPool) Get(hash common.Hash) *txpool.Transaction {
func (p *testTxPool) Get(hash common.Hash) *types.Transaction {
p.lock.Lock()
defer p.lock.Unlock()
if tx := p.pool[hash]; tx != nil {
return &txpool.Transaction{Tx: tx}
}
return nil
return p.pool[hash]
}
// Add appends a batch of transactions to the pool, and notifies any
// listeners if the addition channel is non nil
func (p *testTxPool) Add(txs []*txpool.Transaction, local bool, sync bool) []error {
unwrapped := make([]*types.Transaction, len(txs))
for i, tx := range txs {
unwrapped[i] = tx.Tx
}
func (p *testTxPool) Add(txs []*types.Transaction, local bool, sync bool) []error {
p.lock.Lock()
defer p.lock.Unlock()
for _, tx := range unwrapped {
for _, tx := range txs {
p.pool[tx.Hash()] = tx
}
p.txFeed.Send(core.NewTxsEvent{Txs: unwrapped})
return make([]error, len(unwrapped))
p.txFeed.Send(core.NewTxsEvent{Txs: txs})
return make([]error, len(txs))
}
// Pending returns all the transactions known to the pool
@ -118,7 +109,7 @@ func (p *testTxPool) Pending(enforceTips bool) map[common.Address][]*txpool.Lazy
for _, tx := range batch {
pending[addr] = append(pending[addr], &txpool.LazyTransaction{
Hash: tx.Hash(),
Tx: &txpool.Transaction{Tx: tx},
Tx: tx,
Time: tx.Time(),
GasFeeCap: tx.GasFeeCap(),
GasTipCap: tx.GasTipCap(),

View file

@ -81,8 +81,8 @@ func (p *Peer) broadcastTransactions() {
)
for i := 0; i < len(queue) && size < maxTxPacketSize; i++ {
if tx := p.txpool.Get(queue[i]); tx != nil {
txs = append(txs, tx.Tx)
size += common.StorageSize(tx.Tx.Size())
txs = append(txs, tx)
size += common.StorageSize(tx.Size())
}
hashesCount++
}
@ -151,8 +151,8 @@ func (p *Peer) announceTransactions() {
for count = 0; count < len(queue) && size < maxTxPacketSize; count++ {
if tx := p.txpool.Get(queue[count]); tx != nil {
pending = append(pending, queue[count])
pendingTypes = append(pendingTypes, tx.Tx.Type())
pendingSizes = append(pendingSizes, uint32(tx.Tx.Size()))
pendingTypes = append(pendingTypes, tx.Type())
pendingSizes = append(pendingSizes, uint32(tx.Size()))
size += common.HashLength
}
}

View file

@ -23,7 +23,7 @@ import (
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/core"
"github.com/ethereum/go-ethereum/core/txpool"
"github.com/ethereum/go-ethereum/core/types"
"github.com/ethereum/go-ethereum/metrics"
"github.com/ethereum/go-ethereum/p2p"
"github.com/ethereum/go-ethereum/p2p/enode"
@ -90,7 +90,7 @@ type Backend interface {
// TxPool defines the methods needed by the protocol handler to serve transactions.
type TxPool interface {
// Get retrieves the transaction from the local txpool with the given hash.
Get(hash common.Hash) *txpool.Transaction
Get(hash common.Hash) *types.Transaction
}
// MakeProtocols constructs the P2P protocol definitions for `eth`.

View file

@ -503,7 +503,7 @@ func answerGetPooledTransactions(backend Backend, query GetPooledTransactionsPac
continue
}
// If known, encode and queue for response packet
if encoded, err := rlp.EncodeToBytes(tx.Tx); err != nil {
if encoded, err := rlp.EncodeToBytes(tx); err != nil {
log.Error("Failed to encode transaction", "err", err)
} else {
hashes = append(hashes, hash)

View file

@ -1417,8 +1417,8 @@ type kv struct {
k, v []byte
}
func (k *kv) less(other *kv) bool {
return bytes.Compare(k.k, other.k) < 0
func (k *kv) cmp(other *kv) int {
return bytes.Compare(k.k, other.k)
}
func key32(i uint64) []byte {
@ -1478,7 +1478,7 @@ func makeAccountTrieNoStorage(n int, scheme string) (string, *trie.Trie, []*kv)
accTrie.MustUpdate(elem.k, elem.v)
entries = append(entries, elem)
}
slices.SortFunc(entries, (*kv).less)
slices.SortFunc(entries, (*kv).cmp)
// Commit the state changes into db and re-create the trie
// for accessing later.
@ -1540,7 +1540,7 @@ func makeBoundaryAccountTrie(scheme string, n int) (string, *trie.Trie, []*kv) {
accTrie.MustUpdate(elem.k, elem.v)
entries = append(entries, elem)
}
slices.SortFunc(entries, (*kv).less)
slices.SortFunc(entries, (*kv).cmp)
// Commit the state changes into db and re-create the trie
// for accessing later.
@ -1587,7 +1587,7 @@ func makeAccountTrieWithStorageWithUniqueStorage(scheme string, accounts, slots
storageRoots[common.BytesToHash(key)] = stRoot
storageEntries[common.BytesToHash(key)] = stEntries
}
slices.SortFunc(entries, (*kv).less)
slices.SortFunc(entries, (*kv).cmp)
// Commit account trie
root, set, _ := accTrie.Commit(true)
@ -1652,7 +1652,7 @@ func makeAccountTrieWithStorage(scheme string, accounts, slots int, code, bounda
storageRoots[common.BytesToHash(key)] = stRoot
storageEntries[common.BytesToHash(key)] = stEntries
}
slices.SortFunc(entries, (*kv).less)
slices.SortFunc(entries, (*kv).cmp)
// Commit account trie
root, set, _ := accTrie.Commit(true)
@ -1696,7 +1696,7 @@ func makeStorageTrieWithSeed(owner common.Hash, n, seed uint64, db *trie.Databas
trie.MustUpdate(elem.k, elem.v)
entries = append(entries, elem)
}
slices.SortFunc(entries, (*kv).less)
slices.SortFunc(entries, (*kv).cmp)
root, nodes, _ := trie.Commit(false)
return root, nodes, entries
}
@ -1747,7 +1747,7 @@ func makeBoundaryStorageTrie(owner common.Hash, n int, db *trie.Database) (commo
trie.MustUpdate(elem.k, elem.v)
entries = append(entries, elem)
}
slices.SortFunc(entries, (*kv).less)
slices.SortFunc(entries, (*kv).cmp)
root, nodes, _ := trie.Commit(false)
return root, nodes, entries
}

View file

@ -790,7 +790,7 @@ func newAccounts(n int) (accounts []Account) {
addr := crypto.PubkeyToAddress(key.PublicKey)
accounts = append(accounts, Account{key: key, addr: addr})
}
slices.SortFunc(accounts, func(a, b Account) bool { return a.addr.Less(b.addr) })
slices.SortFunc(accounts, func(a, b Account) int { return a.addr.Cmp(b.addr) })
return accounts
}

View file

@ -527,7 +527,7 @@ func makeDataset(size, ksize, vsize int, order bool) ([][]byte, [][]byte) {
vals = append(vals, randBytes(vsize))
}
if order {
slices.SortFunc(keys, func(a, b []byte) bool { return bytes.Compare(a, b) < 0 })
slices.SortFunc(keys, func(a, b []byte) int { return bytes.Compare(a, b) })
}
return keys, vals
}

View file

@ -75,7 +75,7 @@ type Database struct {
seekCompGauge metrics.Gauge // Gauge for tracking the number of table compaction caused by read opt
manualMemAllocGauge metrics.Gauge // Gauge to track the amount of memory that has been manually allocated (not a part of runtime/GC)
levelsGauge [7]metrics.Gauge // Gauge for tracking the number of tables in levels
levelsGauge []metrics.Gauge // Gauge for tracking the number of tables in levels
quitLock sync.Mutex // Mutex protecting the quit channel access
quitChan chan chan error // Quit channel to stop the metrics collection before closing the database
@ -146,13 +146,8 @@ func NewCustom(file string, namespace string, customize func(options *opt.Option
ldb.seekCompGauge = metrics.NewRegisteredGauge(namespace+"compact/seek", nil)
ldb.manualMemAllocGauge = metrics.NewRegisteredGauge(namespace+"memory/manualalloc", nil)
// leveldb has only up to 7 levels
for i := range ldb.levelsGauge {
ldb.levelsGauge[i] = metrics.NewRegisteredGauge(namespace+fmt.Sprintf("tables/level%v", i), nil)
}
// Start up the metrics gathering and return
go ldb.meter(metricsGatheringInterval)
go ldb.meter(metricsGatheringInterval, namespace)
return ldb, nil
}
@ -271,7 +266,7 @@ func (db *Database) Path() string {
// meter periodically retrieves internal leveldb counters and reports them to
// the metrics subsystem.
func (db *Database) meter(refresh time.Duration) {
func (db *Database) meter(refresh time.Duration, namespace string) {
// Create the counters to store current and previous compaction values
compactions := make([][]int64, 2)
for i := 0; i < 2; i++ {
@ -360,8 +355,11 @@ func (db *Database) meter(refresh time.Duration) {
db.nonlevel0CompGauge.Update(int64(stats.NonLevel0Comp))
db.seekCompGauge.Update(int64(stats.SeekComp))
// update tables amount
for i, tables := range stats.LevelTablesCounts {
// Append metrics for additional layers
if i >= len(db.levelsGauge) {
db.levelsGauge = append(db.levelsGauge, metrics.NewRegisteredGauge(namespace+fmt.Sprintf("tables/level%v", i), nil))
}
db.levelsGauge[i].Update(int64(tables))
}

6
go.mod
View file

@ -19,7 +19,7 @@ require (
github.com/deckarep/golang-set/v2 v2.1.0
github.com/docker/docker v1.6.2
github.com/dop251/goja v0.0.0-20230806174421-c933cf95e127
github.com/ethereum/c-kzg-4844 v0.3.0
github.com/ethereum/c-kzg-4844 v0.3.1
github.com/fatih/color v1.7.0
github.com/fjl/gencodec v0.0.0-20230517082657-f9840df7b83e
github.com/fjl/memsize v0.0.0-20190710130421-bcb5799ab5e5
@ -63,7 +63,7 @@ require (
github.com/urfave/cli/v2 v2.24.1
go.uber.org/automaxprocs v1.5.2
golang.org/x/crypto v0.9.0
golang.org/x/exp v0.0.0-20230515195305-f3d0a9c9a5cc
golang.org/x/exp v0.0.0-20230810033253-352e893a4cad
golang.org/x/sync v0.3.0
golang.org/x/sys v0.9.0
golang.org/x/text v0.9.0
@ -125,7 +125,7 @@ require (
github.com/tklauser/go-sysconf v0.3.5 // indirect
github.com/tklauser/numcpus v0.2.2 // indirect
github.com/xrash/smetrics v0.0.0-20201216005158-039620a65673 // indirect
golang.org/x/mod v0.10.0 // indirect
golang.org/x/mod v0.11.0 // indirect
golang.org/x/net v0.10.0 // indirect
golang.org/x/xerrors v0.0.0-20220517211312-f3a8303e98df // indirect
google.golang.org/protobuf v1.28.1 // indirect

12
go.sum
View file

@ -125,8 +125,8 @@ github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.m
github.com/envoyproxy/go-control-plane v0.9.9-0.20210217033140-668b12f5399d/go.mod h1:cXg6YxExXjJnVBQHBLXeUAgxn2UodCpnH306RInaBQk=
github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c=
github.com/etcd-io/bbolt v1.3.3/go.mod h1:ZF2nL25h33cCyBtcyWeZ2/I3HQOfTP+0PIEvHjkjCrw=
github.com/ethereum/c-kzg-4844 v0.3.0 h1:3Y3hD6l5i0dEYsBL50C+Om644kve3pNqoAcvE26o9zI=
github.com/ethereum/c-kzg-4844 v0.3.0/go.mod h1:WI2Nd82DMZAAZI1wV2neKGost9EKjvbpQR9OqE5Qqa8=
github.com/ethereum/c-kzg-4844 v0.3.1 h1:sR65+68+WdnMKxseNWxSJuAv2tsUrihTpVBTfM/U5Zg=
github.com/ethereum/c-kzg-4844 v0.3.1/go.mod h1:VewdlzQmpT5QSrVhbBuGoCdFJkpaJlO1aQputP83wc0=
github.com/fasthttp-contrib/websocket v0.0.0-20160511215533-1f3b11f56072/go.mod h1:duJ4Jxv5lDcvg4QuQr0oowTf7dz4/CR8NtyCooz9HL8=
github.com/fatih/color v1.7.0 h1:DkWD4oS2D8LGGgTQ6IvwJJXSL5Vp2ffcQg58nFV38Ys=
github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4=
@ -479,8 +479,8 @@ golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5y
golang.org/x/crypto v0.9.0 h1:LF6fAI+IutBocDJ2OT0Q1g8plpYljMZ4+lty+dsqw3g=
golang.org/x/crypto v0.9.0/go.mod h1:yrmDGqONDYtNj3tH8X9dzUun2m2lzPa9ngI6/RUPGR0=
golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
golang.org/x/exp v0.0.0-20230515195305-f3d0a9c9a5cc h1:mCRnTeVUjcrhlRmO0VK8a6k6Rrf6TF9htwo2pJVSjIU=
golang.org/x/exp v0.0.0-20230515195305-f3d0a9c9a5cc/go.mod h1:V1LtkGg67GoY2N1AnLN78QLrzxkLyJw7RJb1gzOOz9w=
golang.org/x/exp v0.0.0-20230810033253-352e893a4cad h1:g0bG7Z4uG+OgH2QDODnjp6ggkk1bJDsINcuWmJN1iJU=
golang.org/x/exp v0.0.0-20230810033253-352e893a4cad/go.mod h1:FXUEEKJgO7OQYeo8N01OfiKP8RXMtf6e8aTskBGqWdc=
golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=
golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU=
golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
@ -490,8 +490,8 @@ 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/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4=
golang.org/x/mod v0.10.0 h1:lFO9qtOdlre5W1jxS3r/4szv2/6iXxScdzjoBMXNhYk=
golang.org/x/mod v0.10.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs=
golang.org/x/mod v0.11.0 h1:bUO06HqtnRcc/7l71XBe4WcqTZ+3AH1J59zWDDwLKgU=
golang.org/x/mod v0.11.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-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=

View file

@ -28,12 +28,13 @@ import (
var (
// These flags override values in build env.
GitCommitFlag = flag.String("git-commit", "", `Overrides git commit hash embedded into executables`)
GitBranchFlag = flag.String("git-branch", "", `Overrides git branch being built`)
GitTagFlag = flag.String("git-tag", "", `Overrides git tag being built`)
BuildnumFlag = flag.String("buildnum", "", `Overrides CI build number`)
PullRequestFlag = flag.Bool("pull-request", false, `Overrides pull request status of the build`)
CronJobFlag = flag.Bool("cron-job", false, `Overrides cron job status of the build`)
GitCommitFlag = flag.String("git-commit", "", `Overrides git commit hash embedded into executables`)
GitBranchFlag = flag.String("git-branch", "", `Overrides git branch being built`)
GitTagFlag = flag.String("git-tag", "", `Overrides git tag being built`)
BuildnumFlag = flag.String("buildnum", "", `Overrides CI build number`)
PullRequestFlag = flag.Bool("pull-request", false, `Overrides pull request status of the build`)
CronJobFlag = flag.Bool("cron-job", false, `Overrides cron job status of the build`)
UbuntuVersionFlag = flag.String("ubuntu", "", `Sets the ubuntu version being built for`)
)
// Environment contains metadata provided by the build environment.
@ -43,6 +44,7 @@ type Environment struct {
Repo string // name of GitHub repo
Commit, Date, Branch, Tag string // Git info
Buildnum string
UbuntuVersion string // Ubuntu version being built for
IsPullRequest bool
IsCronJob bool
}
@ -168,5 +170,8 @@ func applyEnvFlags(env Environment) Environment {
if *CronJobFlag {
env.IsCronJob = true
}
if *UbuntuVersionFlag != "" {
env.UbuntuVersion = *UbuntuVersionFlag
}
return env
}

View file

@ -54,8 +54,8 @@ func (g *GoToolchain) Go(command string, args ...string) *exec.Cmd {
tool.Env = append(tool.Env, "CC="+os.Getenv("CC"))
}
// CKZG by default is not portable, append the necessary build flags to make
// it not rely on modern CPU instructions and enable linking against
tool.Env = append(tool.Env, "CGO_CFLAGS=-D__BLST_PORTABLE__")
// it not rely on modern CPU instructions and enable linking against.
tool.Env = append(tool.Env, "CGO_CFLAGS=-O2 -g -D__BLST_PORTABLE__")
return tool
}

View file

@ -817,7 +817,7 @@ func newAccounts(n int) (accounts []Account) {
addr := crypto.PubkeyToAddress(key.PublicKey)
accounts = append(accounts, Account{key: key, addr: addr})
}
slices.SortFunc(accounts, func(a, b Account) bool { return a.addr.Less(b.addr) })
slices.SortFunc(accounts, func(a, b Account) int { return a.addr.Cmp(b.addr) })
return accounts
}

View file

@ -518,7 +518,7 @@ func handleSendTx(msg Decoder) (serveRequestFn, uint64, uint64, error) {
hash := tx.Hash()
stats[i] = txStatus(backend, hash)
if stats[i].Status == txpool.TxStatusUnknown {
if errs := backend.TxPool().Add([]*txpool.Transaction{{Tx: tx}}, false, backend.AddTxsSync()); errs[0] != nil {
if errs := backend.TxPool().Add([]*types.Transaction{tx}, false, backend.AddTxsSync()); errs[0] != nil {
stats[i].Error = errs[0].Error()
continue
}

View file

@ -215,8 +215,14 @@ func (sq *servingQueue) freezePeers() {
tasks.list = append(tasks.list, task)
tasks.sumTime += task.expTime
}
slices.SortFunc(peerList, func(a, b *peerTasks) bool {
return a.priority < b.priority
slices.SortFunc(peerList, func(a, b *peerTasks) int {
if a.priority < b.priority {
return -1
}
if a.priority > b.priority {
return 1
}
return 0
})
drop := true
for _, tasks := range peerList {

View file

@ -369,8 +369,14 @@ func (l *Limiter) dropRequests() {
priority: w / float64(nq.sumCost),
})
}
slices.SortFunc(list, func(a, b dropListItem) bool {
return a.priority < b.priority
slices.SortFunc(list, func(a, b dropListItem) int {
if a.priority < b.priority {
return -1
}
if a.priority < b.priority {
return 1
}
return 0
})
for _, item := range list {
for _, request := range item.nq.queue {

View file

@ -3,6 +3,7 @@ package metrics
import (
"fmt"
"io"
"strings"
"time"
"golang.org/x/exp/slices"
@ -23,8 +24,7 @@ func WriteOnce(r Registry, w io.Writer) {
r.Each(func(name string, i interface{}) {
namedMetrics = append(namedMetrics, namedMetric{name, i})
})
slices.SortFunc(namedMetrics, namedMetric.less)
slices.SortFunc(namedMetrics, namedMetric.cmp)
for _, namedMetric := range namedMetrics {
switch metric := namedMetric.m.(type) {
case Counter:
@ -92,6 +92,6 @@ type namedMetric struct {
m interface{}
}
func (m namedMetric) less(other namedMetric) bool {
return m.name < other.name
func (m namedMetric) cmp(other namedMetric) int {
return strings.Compare(m.name, other.name)
}

View file

@ -14,7 +14,7 @@ func TestMetricsSorting(t *testing.T) {
{name: "ggg"},
}
slices.SortFunc(namedMetrics, namedMetric.less)
slices.SortFunc(namedMetrics, namedMetric.cmp)
for i, name := range []string{"bbb", "fff", "ggg", "zzz"} {
if namedMetrics[i].name != name {
t.Fail()

View file

@ -88,7 +88,7 @@ func testTransactionPriceNonceSort(t *testing.T, baseFee *big.Int) {
}
groups[addr] = append(groups[addr], &txpool.LazyTransaction{
Hash: tx.Hash(),
Tx: &txpool.Transaction{Tx: tx},
Tx: tx,
Time: tx.Time(),
GasFeeCap: tx.GasFeeCap(),
GasTipCap: tx.GasTipCap(),
@ -101,7 +101,7 @@ func testTransactionPriceNonceSort(t *testing.T, baseFee *big.Int) {
txs := types.Transactions{}
for tx := txset.Peek(); tx != nil; tx = txset.Peek() {
txs = append(txs, tx.Tx.Tx)
txs = append(txs, tx.Tx)
txset.Shift()
}
if len(txs) != expectedCount {
@ -153,7 +153,7 @@ func TestTransactionTimeSort(t *testing.T) {
groups[addr] = append(groups[addr], &txpool.LazyTransaction{
Hash: tx.Hash(),
Tx: &txpool.Transaction{Tx: tx},
Tx: tx,
Time: tx.Time(),
GasFeeCap: tx.GasFeeCap(),
GasTipCap: tx.GasTipCap(),
@ -164,7 +164,7 @@ func TestTransactionTimeSort(t *testing.T) {
txs := types.Transactions{}
for tx := txset.Peek(); tx != nil; tx = txset.Peek() {
txs = append(txs, tx.Tx.Tx)
txs = append(txs, tx.Tx)
txset.Shift()
}
if len(txs) != len(keys) {

View file

@ -30,7 +30,6 @@ import (
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/common/fdlimit"
"github.com/ethereum/go-ethereum/core"
"github.com/ethereum/go-ethereum/core/txpool"
"github.com/ethereum/go-ethereum/core/txpool/legacypool"
"github.com/ethereum/go-ethereum/core/types"
"github.com/ethereum/go-ethereum/crypto"
@ -133,7 +132,7 @@ func main() {
if err != nil {
panic(err)
}
if err := backend.TxPool().Add([]*txpool.Transaction{{Tx: tx}}, true, false); err != nil {
if err := backend.TxPool().Add([]*types.Transaction{tx}, true, false); err != nil {
panic(err)
}
nonces[index]++

View file

@ -539,7 +539,7 @@ func (w *worker) mainLoop() {
acc, _ := types.Sender(w.current.signer, tx)
txs[acc] = append(txs[acc], &txpool.LazyTransaction{
Hash: tx.Hash(),
Tx: &txpool.Transaction{Tx: tx},
Tx: tx.WithoutBlobTxSidecar(),
Time: tx.Time(),
GasFeeCap: tx.GasFeeCap(),
GasTipCap: tx.GasTipCap(),
@ -734,18 +734,18 @@ func (w *worker) updateSnapshot(env *environment) {
w.snapshotState = env.state.Copy()
}
func (w *worker) commitTransaction(env *environment, tx *txpool.Transaction) ([]*types.Log, error) {
func (w *worker) commitTransaction(env *environment, tx *types.Transaction) ([]*types.Log, error) {
var (
snap = env.state.Snapshot()
gp = env.gasPool.Gas()
)
receipt, err := core.ApplyTransaction(w.chainConfig, w.chain, &env.coinbase, env.gasPool, env.state, env.header, tx.Tx, &env.header.GasUsed, *w.chain.GetVMConfig())
receipt, err := core.ApplyTransaction(w.chainConfig, w.chain, &env.coinbase, env.gasPool, env.state, env.header, tx, &env.header.GasUsed, *w.chain.GetVMConfig())
if err != nil {
env.state.RevertToSnapshot(snap)
env.gasPool.SetGas(gp)
return nil, err
}
env.txs = append(env.txs, tx.Tx)
env.txs = append(env.txs, tx)
env.receipts = append(env.receipts, receipt)
return receipt.Logs, nil
@ -778,30 +778,30 @@ func (w *worker) commitTransactions(env *environment, txs *transactionsByPriceAn
tx := ltx.Resolve()
if tx == nil {
log.Warn("Ignoring evicted transaction")
txs.Pop()
continue
}
// Error may be ignored here. The error has already been checked
// during transaction acceptance is the transaction pool.
from, _ := types.Sender(env.signer, tx.Tx)
from, _ := types.Sender(env.signer, tx)
// Check whether the tx is replay protected. If we're not in the EIP155 hf
// phase, start ignoring the sender until we do.
if tx.Tx.Protected() && !w.chainConfig.IsEIP155(env.header.Number) {
log.Trace("Ignoring reply protected transaction", "hash", tx.Tx.Hash(), "eip155", w.chainConfig.EIP155Block)
if tx.Protected() && !w.chainConfig.IsEIP155(env.header.Number) {
log.Trace("Ignoring reply protected transaction", "hash", tx.Hash(), "eip155", w.chainConfig.EIP155Block)
txs.Pop()
continue
}
// Start executing the transaction
env.state.SetTxContext(tx.Tx.Hash(), env.tcount)
env.state.SetTxContext(tx.Hash(), env.tcount)
logs, err := w.commitTransaction(env, tx)
switch {
case errors.Is(err, core.ErrNonceTooLow):
// New head notification data race between the transaction pool and miner, shift
log.Trace("Skipping transaction with low nonce", "sender", from, "nonce", tx.Tx.Nonce())
log.Trace("Skipping transaction with low nonce", "sender", from, "nonce", tx.Nonce())
txs.Shift()
case errors.Is(err, nil):
@ -813,7 +813,7 @@ func (w *worker) commitTransactions(env *environment, txs *transactionsByPriceAn
default:
// Transaction is regarded as invalid, drop all consecutive transactions from
// the same sender because of `nonce-too-high` clause.
log.Debug("Transaction failed, account skipped", "hash", tx.Tx.Hash(), "err", err)
log.Debug("Transaction failed, account skipped", "hash", tx.Hash(), "err", err)
txs.Pop()
}
}

View file

@ -63,7 +63,7 @@ var (
testUserAddress = crypto.PubkeyToAddress(testUserKey.PublicKey)
// Test transactions
pendingTxs []*txpool.Transaction
pendingTxs []*types.Transaction
newTxs []*types.Transaction
testConfig = &Config{
@ -93,7 +93,7 @@ func init() {
Gas: params.TxGas,
GasPrice: big.NewInt(params.InitialBaseFee),
})
pendingTxs = append(pendingTxs, &txpool.Transaction{Tx: tx1})
pendingTxs = append(pendingTxs, tx1)
tx2 := types.MustSignNewTx(testBankKey, signer, &types.LegacyTx{
Nonce: 1,
@ -194,8 +194,8 @@ func TestGenerateAndImportBlock(t *testing.T) {
w.start()
for i := 0; i < 5; i++ {
b.txPool.Add([]*txpool.Transaction{{Tx: b.newRandomTx(true)}}, true, false)
b.txPool.Add([]*txpool.Transaction{{Tx: b.newRandomTx(false)}}, true, false)
b.txPool.Add([]*types.Transaction{b.newRandomTx(true)}, true, false)
b.txPool.Add([]*types.Transaction{b.newRandomTx(false)}, true, false)
select {
case ev := <-sub.Chan():

View file

@ -217,14 +217,14 @@ func nodeEqual(n1 *enode.Node, n2 *enode.Node) bool {
}
func sortByID(nodes []*enode.Node) {
slices.SortFunc(nodes, func(a, b *enode.Node) bool {
return string(a.ID().Bytes()) < string(b.ID().Bytes())
slices.SortFunc(nodes, func(a, b *enode.Node) int {
return bytes.Compare(a.ID().Bytes(), b.ID().Bytes())
})
}
func sortedByDistanceTo(distbase enode.ID, slice []*node) bool {
return slices.IsSortedFunc(slice, func(a, b *node) bool {
return enode.DistCmp(distbase, a.ID(), b.ID()) < 0
return slices.IsSortedFunc(slice, func(a, b *node) int {
return enode.DistCmp(distbase, a.ID(), b.ID())
})
}

View file

@ -302,8 +302,8 @@ func (tn *preminedTestnet) closest(n int) (nodes []*enode.Node) {
nodes = append(nodes, tn.node(d, i))
}
}
slices.SortFunc(nodes, func(a, b *enode.Node) bool {
return enode.DistCmp(tn.target.id(), a.ID(), b.ID()) < 0
slices.SortFunc(nodes, func(a, b *enode.Node) int {
return enode.DistCmp(tn.target.id(), a.ID(), b.ID())
})
return nodes[:n]
}

View file

@ -61,8 +61,8 @@ func TestUDPv5_lookupE2E(t *testing.T) {
for i := range nodes {
expectedResult[i] = nodes[i].Self()
}
slices.SortFunc(expectedResult, func(a, b *enode.Node) bool {
return enode.DistCmp(target.ID(), a.ID(), b.ID()) < 0
slices.SortFunc(expectedResult, func(a, b *enode.Node) int {
return enode.DistCmp(target.ID(), a.ID(), b.ID())
})
// Do the lookup.

View file

@ -214,8 +214,8 @@ func (t *Tree) build(entries []entry) entry {
}
func sortByID(nodes []*enode.Node) []*enode.Node {
slices.SortFunc(nodes, func(a, b *enode.Node) bool {
return bytes.Compare(a.ID().Bytes(), b.ID().Bytes()) < 0
slices.SortFunc(nodes, func(a, b *enode.Node) int {
return bytes.Compare(a.ID().Bytes(), b.ID().Bytes())
})
return nodes
}

View file

@ -386,7 +386,7 @@ func countMatchingProtocols(protocols []Protocol, caps []Cap) int {
// matchProtocols creates structures for matching named subprotocols.
func matchProtocols(protocols []Protocol, caps []Cap, rw MsgReadWriter) map[string]*protoRW {
slices.SortFunc(caps, Cap.Less)
slices.SortFunc(caps, Cap.Cmp)
offset := baseProtocolLength
result := make(map[string]*protoRW)

View file

@ -18,6 +18,7 @@ package p2p
import (
"fmt"
"strings"
"github.com/ethereum/go-ethereum/p2p/enode"
"github.com/ethereum/go-ethereum/p2p/enr"
@ -77,10 +78,16 @@ func (cap Cap) String() string {
return fmt.Sprintf("%s/%d", cap.Name, cap.Version)
}
// Less defines the canonical sorting order of capabilities.
func (cap Cap) Less(other Cap) bool {
// Cmp defines the canonical sorting order of capabilities.
func (cap Cap) Cmp(other Cap) int {
if cap.Name == other.Name {
return cap.Version < other.Version
if cap.Version < other.Version {
return -1
}
if cap.Version > other.Version {
return 1
}
return 0
}
return cap.Name < other.Name
return strings.Compare(cap.Name, other.Name)
}

View file

@ -510,7 +510,7 @@ func (srv *Server) setupLocalNode() error {
for _, p := range srv.Protocols {
srv.ourHandshake.Caps = append(srv.ourHandshake.Caps, p.cap())
}
slices.SortFunc(srv.ourHandshake.Caps, Cap.Less)
slices.SortFunc(srv.ourHandshake.Caps, Cap.Cmp)
// Create the local node.
db, err := enode.OpenDB(srv.NodeDatabase)

View file

@ -278,24 +278,21 @@ type websocketCodec struct {
conn *websocket.Conn
info PeerInfo
wg sync.WaitGroup
pingReset chan struct{}
wg sync.WaitGroup
pingReset chan struct{}
pongReceived chan struct{}
}
func newWebsocketCodec(conn *websocket.Conn, host string, req http.Header) ServerCodec {
conn.SetReadLimit(wsMessageSizeLimit)
conn.SetPongHandler(func(appData string) error {
conn.SetReadDeadline(time.Time{})
return nil
})
encode := func(v interface{}, isErrorResponse bool) error {
return conn.WriteJSON(v)
}
wc := &websocketCodec{
jsonCodec: NewFuncCodec(conn, encode, conn.ReadJSON).(*jsonCodec),
conn: conn,
pingReset: make(chan struct{}, 1),
jsonCodec: NewFuncCodec(conn, encode, conn.ReadJSON).(*jsonCodec),
conn: conn,
pingReset: make(chan struct{}, 1),
pongReceived: make(chan struct{}),
info: PeerInfo{
Transport: "ws",
RemoteAddr: conn.RemoteAddr().String(),
@ -306,6 +303,13 @@ func newWebsocketCodec(conn *websocket.Conn, host string, req http.Header) Serve
wc.info.HTTP.Origin = req.Get("Origin")
wc.info.HTTP.UserAgent = req.Get("User-Agent")
// Start pinger.
conn.SetPongHandler(func(appData string) error {
select {
case wc.pongReceived <- struct{}{}:
case <-wc.closed():
}
return nil
})
wc.wg.Add(1)
go wc.pingLoop()
return wc
@ -334,26 +338,31 @@ func (wc *websocketCodec) writeJSON(ctx context.Context, v interface{}, isError
// pingLoop sends periodic ping frames when the connection is idle.
func (wc *websocketCodec) pingLoop() {
var timer = time.NewTimer(wsPingInterval)
var pingTimer = time.NewTimer(wsPingInterval)
defer wc.wg.Done()
defer timer.Stop()
defer pingTimer.Stop()
for {
select {
case <-wc.closed():
return
case <-wc.pingReset:
if !timer.Stop() {
<-timer.C
if !pingTimer.Stop() {
<-pingTimer.C
}
timer.Reset(wsPingInterval)
case <-timer.C:
pingTimer.Reset(wsPingInterval)
case <-pingTimer.C:
wc.jsonCodec.encMu.Lock()
wc.conn.SetWriteDeadline(time.Now().Add(wsPingWriteTimeout))
wc.conn.WriteMessage(websocket.PingMessage, nil)
wc.conn.SetReadDeadline(time.Now().Add(wsPongTimeout))
wc.jsonCodec.encMu.Unlock()
timer.Reset(wsPingInterval)
pingTimer.Reset(wsPingInterval)
case <-wc.pongReceived:
wc.conn.SetReadDeadline(time.Time{})
}
}
}

View file

@ -98,8 +98,8 @@ func (f *fuzzer) fuzz() int {
if len(entries) <= 1 {
return 0
}
slices.SortFunc(entries, func(a, b *kv) bool {
return bytes.Compare(a.k, b.k) < 0
slices.SortFunc(entries, func(a, b *kv) int {
return bytes.Compare(a.k, b.k)
})
var ok = 0

View file

@ -182,8 +182,8 @@ func (f *fuzzer) fuzz() int {
dbA.Commit(rootA, false)
// Stacktrie requires sorted insertion
slices.SortFunc(vals, func(a, b kv) bool {
return bytes.Compare(a.k, b.k) < 0
slices.SortFunc(vals, func(a, b kv) int {
return bytes.Compare(a.k, b.k)
})
for _, kv := range vals {
if f.debugging {

View file

@ -25,7 +25,6 @@ import (
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/common/mclock"
"github.com/ethereum/go-ethereum/core/txpool"
"github.com/ethereum/go-ethereum/core/types"
"github.com/ethereum/go-ethereum/eth/fetcher"
)
@ -80,7 +79,7 @@ func Fuzz(input []byte) int {
f := fetcher.NewTxFetcherForTests(
func(common.Hash) bool { return false },
func(txs []*txpool.Transaction) []error {
func(txs []*types.Transaction) []error {
return make([]error, len(txs))
},
func(string, []common.Hash) error { return nil },

View file

@ -81,8 +81,8 @@ type kv struct {
t bool
}
func (k *kv) less(other *kv) bool {
return bytes.Compare(k.k, other.k) < 0
func (k *kv) cmp(other *kv) int {
return bytes.Compare(k.k, other.k)
}
func TestIteratorLargeData(t *testing.T) {

View file

@ -173,7 +173,7 @@ func TestRangeProof(t *testing.T) {
for _, kv := range vals {
entries = append(entries, kv)
}
slices.SortFunc(entries, (*kv).less)
slices.SortFunc(entries, (*kv).cmp)
for i := 0; i < 500; i++ {
start := mrand.Intn(len(entries))
end := mrand.Intn(len(entries)-start) + start + 1
@ -206,7 +206,7 @@ func TestRangeProofWithNonExistentProof(t *testing.T) {
for _, kv := range vals {
entries = append(entries, kv)
}
slices.SortFunc(entries, (*kv).less)
slices.SortFunc(entries, (*kv).cmp)
for i := 0; i < 500; i++ {
start := mrand.Intn(len(entries))
end := mrand.Intn(len(entries)-start) + start + 1
@ -278,7 +278,7 @@ func TestRangeProofWithInvalidNonExistentProof(t *testing.T) {
for _, kv := range vals {
entries = append(entries, kv)
}
slices.SortFunc(entries, (*kv).less)
slices.SortFunc(entries, (*kv).cmp)
// Case 1
start, end := 100, 200
@ -335,7 +335,7 @@ func TestOneElementRangeProof(t *testing.T) {
for _, kv := range vals {
entries = append(entries, kv)
}
slices.SortFunc(entries, (*kv).less)
slices.SortFunc(entries, (*kv).cmp)
// One element with existent edge proof, both edge proofs
// point to the SAME key.
@ -422,7 +422,7 @@ func TestAllElementsProof(t *testing.T) {
for _, kv := range vals {
entries = append(entries, kv)
}
slices.SortFunc(entries, (*kv).less)
slices.SortFunc(entries, (*kv).cmp)
var k [][]byte
var v [][]byte
@ -474,7 +474,7 @@ func TestSingleSideRangeProof(t *testing.T) {
trie.MustUpdate(value.k, value.v)
entries = append(entries, value)
}
slices.SortFunc(entries, (*kv).less)
slices.SortFunc(entries, (*kv).cmp)
var cases = []int{0, 1, 50, 100, 1000, 2000, len(entries) - 1}
for _, pos := range cases {
@ -509,7 +509,7 @@ func TestReverseSingleSideRangeProof(t *testing.T) {
trie.MustUpdate(value.k, value.v)
entries = append(entries, value)
}
slices.SortFunc(entries, (*kv).less)
slices.SortFunc(entries, (*kv).cmp)
var cases = []int{0, 1, 50, 100, 1000, 2000, len(entries) - 1}
for _, pos := range cases {
@ -543,7 +543,7 @@ func TestBadRangeProof(t *testing.T) {
for _, kv := range vals {
entries = append(entries, kv)
}
slices.SortFunc(entries, (*kv).less)
slices.SortFunc(entries, (*kv).cmp)
for i := 0; i < 500; i++ {
start := mrand.Intn(len(entries))
@ -646,7 +646,7 @@ func TestSameSideProofs(t *testing.T) {
for _, kv := range vals {
entries = append(entries, kv)
}
slices.SortFunc(entries, (*kv).less)
slices.SortFunc(entries, (*kv).cmp)
pos := 1000
first := decreaseKey(common.CopyBytes(entries[pos].k))
@ -690,7 +690,7 @@ func TestHasRightElement(t *testing.T) {
trie.MustUpdate(value.k, value.v)
entries = append(entries, value)
}
slices.SortFunc(entries, (*kv).less)
slices.SortFunc(entries, (*kv).cmp)
var cases = []struct {
start int
@ -762,7 +762,7 @@ func TestEmptyRangeProof(t *testing.T) {
for _, kv := range vals {
entries = append(entries, kv)
}
slices.SortFunc(entries, (*kv).less)
slices.SortFunc(entries, (*kv).cmp)
var cases = []struct {
pos int
@ -797,7 +797,7 @@ func TestBloatedProof(t *testing.T) {
for _, kv := range kvs {
entries = append(entries, kv)
}
slices.SortFunc(entries, (*kv).less)
slices.SortFunc(entries, (*kv).cmp)
var keys [][]byte
var vals [][]byte
@ -831,7 +831,7 @@ func TestEmptyValueRangeProof(t *testing.T) {
for _, kv := range values {
entries = append(entries, kv)
}
slices.SortFunc(entries, (*kv).less)
slices.SortFunc(entries, (*kv).cmp)
// Create a new entry with a slightly modified key
mid := len(entries) / 2
@ -875,7 +875,7 @@ func TestAllElementsEmptyValueRangeProof(t *testing.T) {
for _, kv := range values {
entries = append(entries, kv)
}
slices.SortFunc(entries, (*kv).less)
slices.SortFunc(entries, (*kv).cmp)
// Create a new entry with a slightly modified key
mid := len(entries) / 2
@ -981,7 +981,7 @@ func benchmarkVerifyRangeProof(b *testing.B, size int) {
for _, kv := range vals {
entries = append(entries, kv)
}
slices.SortFunc(entries, (*kv).less)
slices.SortFunc(entries, (*kv).cmp)
start := 2
end := start + size
@ -1018,7 +1018,7 @@ func benchmarkVerifyRangeNoProof(b *testing.B, size int) {
for _, kv := range vals {
entries = append(entries, kv)
}
slices.SortFunc(entries, (*kv).less)
slices.SortFunc(entries, (*kv).cmp)
var keys [][]byte
var values [][]byte

View file

@ -262,20 +262,20 @@ func newHistory(root common.Hash, parent common.Hash, block uint64, states *trie
for addr := range states.Accounts {
accountList = append(accountList, addr)
}
slices.SortFunc(accountList, func(a, b common.Address) bool { return a.Less(b) })
slices.SortFunc(accountList, common.Address.Cmp)
for addr, slots := range states.Storages {
slist := make([]common.Hash, 0, len(slots))
for slotHash := range slots {
slist = append(slist, slotHash)
}
slices.SortFunc(slist, func(a, b common.Hash) bool { return a.Less(b) })
slices.SortFunc(slist, common.Hash.Cmp)
storageList[addr] = slist
}
for addr := range states.Incomplete {
incomplete = append(incomplete, addr)
}
slices.SortFunc(incomplete, func(a, b common.Address) bool { return a.Less(b) })
slices.SortFunc(incomplete, common.Address.Cmp)
return &history{
meta: &meta{

View file

@ -21,6 +21,7 @@ import (
"errors"
"fmt"
"io"
"time"
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/core/rawdb"
@ -341,6 +342,14 @@ func (db *Database) Journal(root common.Hash) error {
if l == nil {
return fmt.Errorf("triedb layer [%#x] missing", root)
}
disk := db.tree.bottom()
if l, ok := l.(*diffLayer); ok {
log.Info("Persisting dirty state to disk", "head", l.block, "root", root, "layers", l.id-disk.id+disk.buffer.layers)
} else { // disk layer only on noop runs (likely) or deep reorgs (unlikely)
log.Info("Persisting dirty state to disk", "root", root, "layers", disk.buffer.layers)
}
start := time.Now()
// Run the journaling
db.lock.Lock()
defer db.lock.Unlock()
@ -373,6 +382,6 @@ func (db *Database) Journal(root common.Hash) error {
// Set the db in read only mode to reject all following mutations
db.readOnly = true
log.Info("Stored journal in triedb", "disk", diskroot, "size", common.StorageSize(journal.Len()))
log.Info("Persisted dirty state to disk", "size", common.StorageSize(journal.Len()), "elapsed", common.PrettyDuration(time.Since(start)))
return nil
}

View file

@ -117,7 +117,7 @@ func hash(states map[common.Hash][]byte) (common.Hash, []byte) {
for hash := range states {
hs = append(hs, hash)
}
slices.SortFunc(hs, func(a, b common.Hash) bool { return a.Less(b) })
slices.SortFunc(hs, common.Hash.Cmp)
var input []byte
for _, hash := range hs {

View file

@ -18,10 +18,10 @@ package trienode
import (
"fmt"
"sort"
"strings"
"github.com/ethereum/go-ethereum/common"
"golang.org/x/exp/slices"
)
// Node is a wrapper which contains the encoded blob of the trie node and its
@ -83,9 +83,7 @@ func (set *NodeSet) ForEachWithOrder(callback func(path string, n *Node)) {
paths = append(paths, path)
}
// Bottom-up, the longest path first
slices.SortFunc(paths, func(a, b string) bool {
return a > b // Sort in reverse order
})
sort.Sort(sort.Reverse(sort.StringSlice(paths)))
for _, path := range paths {
callback(path, set.Nodes[path])
}