fix merge conflict

This commit is contained in:
Sina Mahmoodi 2024-03-13 12:48:34 +01:00
commit 0b5975fee3
19 changed files with 273 additions and 127 deletions

View file

@ -16,7 +16,7 @@
// This file contains the implementation for interacting with the Ledger hardware // This file contains the implementation for interacting with the Ledger hardware
// wallets. The wire protocol spec can be found in the Ledger Blue GitHub repo: // wallets. The wire protocol spec can be found in the Ledger Blue GitHub repo:
// https://raw.githubusercontent.com/LedgerHQ/blue-app-eth/master/doc/ethapp.asc // https://github.com/LedgerHQ/app-ethereum/blob/develop/doc/ethapp.adoc
package usbwallet package usbwallet

View file

@ -754,8 +754,8 @@ func makeSidecar(data ...byte) *types.BlobTxSidecar {
) )
for i := range blobs { for i := range blobs {
blobs[i][0] = data[i] blobs[i][0] = data[i]
c, _ := kzg4844.BlobToCommitment(blobs[i]) c, _ := kzg4844.BlobToCommitment(&blobs[i])
p, _ := kzg4844.ComputeBlobProof(blobs[i], c) p, _ := kzg4844.ComputeBlobProof(&blobs[i], c)
commitments = append(commitments, c) commitments = append(commitments, c)
proofs = append(proofs, p) proofs = append(proofs, p)
} }

View file

@ -2,7 +2,7 @@
// Use of this source code is governed by a BSD-style // Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file. // license that can be found in the LICENSE file.
// Adapted from: https://golang.org/src/crypto/cipher/xor.go // Adapted from: https://go.dev/src/crypto/subtle/xor_generic.go
// Package bitutil implements fast bitwise operations. // Package bitutil implements fast bitwise operations.
package bitutil package bitutil

View file

@ -2,7 +2,7 @@
// Use of this source code is governed by a BSD-style // Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file. // license that can be found in the LICENSE file.
// Adapted from: https://golang.org/src/crypto/cipher/xor_test.go // Adapted from: https://go.dev/src/crypto/subtle/xor_test.go
package bitutil package bitutil

View file

@ -637,6 +637,172 @@ func (bc *BlockChain) SetSafe(header *types.Header) {
} }
} }
// rewindPathHead implements the logic of rewindHead in the context of hash scheme.
func (bc *BlockChain) rewindHashHead(head *types.Header, root common.Hash) (*types.Header, uint64) {
var (
limit uint64 // The oldest block that will be searched for this rewinding
beyondRoot = root == common.Hash{} // Flag whether we're beyond the requested root (no root, always true)
pivot = rawdb.ReadLastPivotNumber(bc.db) // Associated block number of pivot point state
rootNumber uint64 // Associated block number of requested root
start = time.Now() // Timestamp the rewinding is restarted
logged = time.Now() // Timestamp last progress log was printed
)
// The oldest block to be searched is determined by the pivot block or a constant
// searching threshold. The rationale behind this is as follows:
//
// - Snap sync is selected if the pivot block is available. The earliest available
// state is the pivot block itself, so there is no sense in going further back.
//
// - Full sync is selected if the pivot block does not exist. The hash database
// periodically flushes the state to disk, and the used searching threshold is
// considered sufficient to find a persistent state, even for the testnet. It
// might be not enough for a chain that is nearly empty. In the worst case,
// the entire chain is reset to genesis, and snap sync is re-enabled on top,
// which is still acceptable.
if pivot != nil {
limit = *pivot
} else if head.Number.Uint64() > params.FullImmutabilityThreshold {
limit = head.Number.Uint64() - params.FullImmutabilityThreshold
}
for {
logger := log.Trace
if time.Since(logged) > time.Second*8 {
logged = time.Now()
logger = log.Info
}
logger("Block state missing, rewinding further", "number", head.Number, "hash", head.Hash(), "elapsed", common.PrettyDuration(time.Since(start)))
// If a root threshold was requested but not yet crossed, check
if !beyondRoot && head.Root == root {
beyondRoot, rootNumber = true, head.Number.Uint64()
}
// If search limit is reached, return the genesis block as the
// new chain head.
if head.Number.Uint64() < limit {
log.Info("Rewinding limit reached, resetting to genesis", "number", head.Number, "hash", head.Hash(), "limit", limit)
return bc.genesisBlock.Header(), rootNumber
}
// If the associated state is not reachable, continue searching
// backwards until an available state is found.
if !bc.HasState(head.Root) {
// If the chain is gapped in the middle, return the genesis
// block as the new chain head.
parent := bc.GetHeader(head.ParentHash, head.Number.Uint64()-1)
if parent == nil {
log.Error("Missing block in the middle, resetting to genesis", "number", head.Number.Uint64()-1, "hash", head.ParentHash)
return bc.genesisBlock.Header(), rootNumber
}
head = parent
// If the genesis block is reached, stop searching.
if head.Number.Uint64() == 0 {
log.Info("Genesis block reached", "number", head.Number, "hash", head.Hash())
return head, rootNumber
}
continue // keep rewinding
}
// Once the available state is found, ensure that the requested root
// has already been crossed. If not, continue rewinding.
if beyondRoot || head.Number.Uint64() == 0 {
log.Info("Rewound to block with state", "number", head.Number, "hash", head.Hash())
return head, rootNumber
}
log.Debug("Skipping block with threshold state", "number", head.Number, "hash", head.Hash(), "root", head.Root)
head = bc.GetHeader(head.ParentHash, head.Number.Uint64()-1) // Keep rewinding
}
}
// rewindPathHead implements the logic of rewindHead in the context of path scheme.
func (bc *BlockChain) rewindPathHead(head *types.Header, root common.Hash) (*types.Header, uint64) {
var (
pivot = rawdb.ReadLastPivotNumber(bc.db) // Associated block number of pivot block
rootNumber uint64 // Associated block number of requested root
// BeyondRoot represents whether the requested root is already
// crossed. The flag value is set to true if the root is empty.
beyondRoot = root == common.Hash{}
// noState represents if the target state requested for search
// is unavailable and impossible to be recovered.
noState = !bc.HasState(root) && !bc.stateRecoverable(root)
start = time.Now() // Timestamp the rewinding is restarted
logged = time.Now() // Timestamp last progress log was printed
)
// Rewind the head block tag until an available state is found.
for {
logger := log.Trace
if time.Since(logged) > time.Second*8 {
logged = time.Now()
logger = log.Info
}
logger("Block state missing, rewinding further", "number", head.Number, "hash", head.Hash(), "elapsed", common.PrettyDuration(time.Since(start)))
// If a root threshold was requested but not yet crossed, check
if !beyondRoot && head.Root == root {
beyondRoot, rootNumber = true, head.Number.Uint64()
}
// If the root threshold hasn't been crossed but the available
// state is reached, quickly determine if the target state is
// possible to be reached or not.
if !beyondRoot && noState && bc.HasState(head.Root) {
beyondRoot = true
log.Info("Disable the search for unattainable state", "root", root)
}
// Check if the associated state is available or recoverable if
// the requested root has already been crossed.
if beyondRoot && (bc.HasState(head.Root) || bc.stateRecoverable(head.Root)) {
break
}
// If pivot block is reached, return the genesis block as the
// new chain head. Theoretically there must be a persistent
// state before or at the pivot block, prevent endless rewinding
// towards the genesis just in case.
if pivot != nil && *pivot >= head.Number.Uint64() {
log.Info("Pivot block reached, resetting to genesis", "number", head.Number, "hash", head.Hash())
return bc.genesisBlock.Header(), rootNumber
}
// If the chain is gapped in the middle, return the genesis
// block as the new chain head
parent := bc.GetHeader(head.ParentHash, head.Number.Uint64()-1) // Keep rewinding
if parent == nil {
log.Error("Missing block in the middle, resetting to genesis", "number", head.Number.Uint64()-1, "hash", head.ParentHash)
return bc.genesisBlock.Header(), rootNumber
}
head = parent
// If the genesis block is reached, stop searching.
if head.Number.Uint64() == 0 {
log.Info("Genesis block reached", "number", head.Number, "hash", head.Hash())
return head, rootNumber
}
}
// Recover if the target state if it's not available yet.
if !bc.HasState(head.Root) {
if err := bc.triedb.Recover(head.Root); err != nil {
log.Crit("Failed to rollback state", "err", err)
}
}
log.Info("Rewound to block with state", "number", head.Number, "hash", head.Hash())
return head, rootNumber
}
// rewindHead searches the available states in the database and returns the associated
// block as the new head block.
//
// If the given root is not empty, then the rewind should attempt to pass the specified
// state root and return the associated block number as well. If the root, typically
// representing the state corresponding to snapshot disk layer, is deemed impassable,
// then block number zero is returned, indicating that snapshot recovery is disabled
// and the whole snapshot should be auto-generated in case of head mismatch.
func (bc *BlockChain) rewindHead(head *types.Header, root common.Hash) (*types.Header, uint64) {
if bc.triedb.Scheme() == rawdb.PathScheme {
return bc.rewindPathHead(head, root)
}
return bc.rewindHashHead(head, root)
}
// setHeadBeyondRoot rewinds the local chain to a new head with the extra condition // setHeadBeyondRoot rewinds the local chain to a new head with the extra condition
// that the rewind must pass the specified state root. This method is meant to be // that the rewind must pass the specified state root. This method is meant to be
// used when rewinding with snapshots enabled to ensure that we go back further than // used when rewinding with snapshots enabled to ensure that we go back further than
@ -655,79 +821,40 @@ func (bc *BlockChain) setHeadBeyondRoot(head uint64, time uint64, root common.Ha
} }
defer bc.chainmu.Unlock() defer bc.chainmu.Unlock()
// Track the block number of the requested root hash var (
var rootNumber uint64 // (no root == always 0) // Track the block number of the requested root hash
rootNumber uint64 // (no root == always 0)
// Retrieve the last pivot block to short circuit rollbacks beyond it and the
// current freezer limit to start nuking id underflown
pivot := rawdb.ReadLastPivotNumber(bc.db)
frozen, _ := bc.db.Ancients()
// Retrieve the last pivot block to short circuit rollbacks beyond it
// and the current freezer limit to start nuking it's underflown.
pivot = rawdb.ReadLastPivotNumber(bc.db)
)
updateFn := func(db ethdb.KeyValueWriter, header *types.Header) (*types.Header, bool) { updateFn := func(db ethdb.KeyValueWriter, header *types.Header) (*types.Header, bool) {
// Rewind the blockchain, ensuring we don't end up with a stateless head // Rewind the blockchain, ensuring we don't end up with a stateless head
// block. Note, depth equality is permitted to allow using SetHead as a // block. Note, depth equality is permitted to allow using SetHead as a
// chain reparation mechanism without deleting any data! // chain reparation mechanism without deleting any data!
if currentBlock := bc.CurrentBlock(); currentBlock != nil && header.Number.Uint64() <= currentBlock.Number.Uint64() { if currentBlock := bc.CurrentBlock(); currentBlock != nil && header.Number.Uint64() <= currentBlock.Number.Uint64() {
newHeadBlock := bc.GetBlock(header.Hash(), header.Number.Uint64()) var newHeadBlock *types.Header
if newHeadBlock == nil { newHeadBlock, rootNumber = bc.rewindHead(header, root)
log.Error("Gap in the chain, rewinding to genesis", "number", header.Number, "hash", header.Hash())
newHeadBlock = bc.genesisBlock
} else {
// Block exists. Keep rewinding until either we find one with state
// or until we exceed the optional threshold root hash
beyondRoot := (root == common.Hash{}) // Flag whether we're beyond the requested root (no root, always true)
for {
// If a root threshold was requested but not yet crossed, check
if root != (common.Hash{}) && !beyondRoot && newHeadBlock.Root() == root {
beyondRoot, rootNumber = true, newHeadBlock.NumberU64()
}
if !bc.HasState(newHeadBlock.Root()) && !bc.stateRecoverable(newHeadBlock.Root()) {
log.Trace("Block state missing, rewinding further", "number", newHeadBlock.NumberU64(), "hash", newHeadBlock.Hash())
if pivot == nil || newHeadBlock.NumberU64() > *pivot {
parent := bc.GetBlock(newHeadBlock.ParentHash(), newHeadBlock.NumberU64()-1)
if parent != nil {
newHeadBlock = parent
continue
}
log.Error("Missing block in the middle, aiming genesis", "number", newHeadBlock.NumberU64()-1, "hash", newHeadBlock.ParentHash())
newHeadBlock = bc.genesisBlock
} else {
log.Trace("Rewind passed pivot, aiming genesis", "number", newHeadBlock.NumberU64(), "hash", newHeadBlock.Hash(), "pivot", *pivot)
newHeadBlock = bc.genesisBlock
}
}
if beyondRoot || newHeadBlock.NumberU64() == 0 {
if !bc.HasState(newHeadBlock.Root()) && bc.stateRecoverable(newHeadBlock.Root()) {
// Rewind to a block with recoverable state. If the state is
// missing, run the state recovery here.
if err := bc.triedb.Recover(newHeadBlock.Root()); err != nil {
log.Crit("Failed to rollback state", "err", err) // Shouldn't happen
}
log.Debug("Rewound to block with state", "number", newHeadBlock.NumberU64(), "hash", newHeadBlock.Hash())
}
break
}
log.Debug("Skipping block with threshold state", "number", newHeadBlock.NumberU64(), "hash", newHeadBlock.Hash(), "root", newHeadBlock.Root())
newHeadBlock = bc.GetBlock(newHeadBlock.ParentHash(), newHeadBlock.NumberU64()-1) // Keep rewinding
}
}
rawdb.WriteHeadBlockHash(db, newHeadBlock.Hash()) rawdb.WriteHeadBlockHash(db, newHeadBlock.Hash())
// Degrade the chain markers if they are explicitly reverted. // Degrade the chain markers if they are explicitly reverted.
// In theory we should update all in-memory markers in the // In theory we should update all in-memory markers in the
// last step, however the direction of SetHead is from high // last step, however the direction of SetHead is from high
// to low, so it's safe to update in-memory markers directly. // to low, so it's safe to update in-memory markers directly.
bc.currentBlock.Store(newHeadBlock.Header()) bc.currentBlock.Store(newHeadBlock)
headBlockGauge.Update(int64(newHeadBlock.NumberU64())) headBlockGauge.Update(int64(newHeadBlock.Number.Uint64()))
// The head state is missing, which is only possible in the path-based // The head state is missing, which is only possible in the path-based
// scheme. This situation occurs when the chain head is rewound below // scheme. This situation occurs when the chain head is rewound below
// the pivot point. In this scenario, there is no possible recovery // the pivot point. In this scenario, there is no possible recovery
// approach except for rerunning a snap sync. Do nothing here until the // approach except for rerunning a snap sync. Do nothing here until the
// state syncer picks it up. // state syncer picks it up.
if !bc.HasState(newHeadBlock.Root()) { if !bc.HasState(newHeadBlock.Root) {
log.Info("Chain is stateless, wait state sync", "number", newHeadBlock.Number(), "hash", newHeadBlock.Hash()) if newHeadBlock.Number.Uint64() != 0 {
log.Crit("Chain is stateless at a non-genesis block")
}
log.Info("Chain is stateless, wait state sync", "number", newHeadBlock.Number, "hash", newHeadBlock.Hash())
} }
} }
// Rewind the snap block in a simpleton way to the target head // Rewind the snap block in a simpleton way to the target head
@ -754,6 +881,7 @@ func (bc *BlockChain) setHeadBeyondRoot(head uint64, time uint64, root common.Ha
// intent afterwards is full block importing, delete the chain segment // intent afterwards is full block importing, delete the chain segment
// between the stateful-block and the sethead target. // between the stateful-block and the sethead target.
var wipe bool var wipe bool
frozen, _ := bc.db.Ancients()
if headNumber+1 < frozen { if headNumber+1 < frozen {
wipe = pivot == nil || headNumber >= *pivot wipe = pivot == nil || headNumber >= *pivot
} }

View file

@ -49,7 +49,7 @@ import (
) )
var ( var (
emptyBlob = kzg4844.Blob{} emptyBlob = new(kzg4844.Blob)
emptyBlobCommit, _ = kzg4844.BlobToCommitment(emptyBlob) emptyBlobCommit, _ = kzg4844.BlobToCommitment(emptyBlob)
emptyBlobProof, _ = kzg4844.ComputeBlobProof(emptyBlob, emptyBlobCommit) emptyBlobProof, _ = kzg4844.ComputeBlobProof(emptyBlob, emptyBlobCommit)
emptyBlobVHash = kzg4844.CalcBlobHashV1(sha256.New(), &emptyBlobCommit) emptyBlobVHash = kzg4844.CalcBlobHashV1(sha256.New(), &emptyBlobCommit)
@ -199,7 +199,7 @@ func makeUnsignedTx(nonce uint64, gasTipCap uint64, gasFeeCap uint64, blobFeeCap
BlobHashes: []common.Hash{emptyBlobVHash}, BlobHashes: []common.Hash{emptyBlobVHash},
Value: uint256.NewInt(100), Value: uint256.NewInt(100),
Sidecar: &types.BlobTxSidecar{ Sidecar: &types.BlobTxSidecar{
Blobs: []kzg4844.Blob{emptyBlob}, Blobs: []kzg4844.Blob{*emptyBlob},
Commitments: []kzg4844.Commitment{emptyBlobCommit}, Commitments: []kzg4844.Commitment{emptyBlobCommit},
Proofs: []kzg4844.Proof{emptyBlobProof}, Proofs: []kzg4844.Proof{emptyBlobProof},
}, },

View file

@ -162,7 +162,7 @@ func validateBlobSidecar(hashes []common.Hash, sidecar *types.BlobTxSidecar) err
// Blob commitments match with the hashes in the transaction, verify the // Blob commitments match with the hashes in the transaction, verify the
// blobs themselves via KZG // blobs themselves via KZG
for i := range sidecar.Blobs { for i := range sidecar.Blobs {
if err := kzg4844.VerifyBlobProof(sidecar.Blobs[i], sidecar.Commitments[i], sidecar.Proofs[i]); err != nil { 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 fmt.Errorf("invalid blob %d: %v", i, err)
} }
} }

View file

@ -59,7 +59,7 @@ func TestBlobTxSize(t *testing.T) {
} }
var ( var (
emptyBlob = kzg4844.Blob{} emptyBlob = new(kzg4844.Blob)
emptyBlobCommit, _ = kzg4844.BlobToCommitment(emptyBlob) emptyBlobCommit, _ = kzg4844.BlobToCommitment(emptyBlob)
emptyBlobProof, _ = kzg4844.ComputeBlobProof(emptyBlob, emptyBlobCommit) emptyBlobProof, _ = kzg4844.ComputeBlobProof(emptyBlob, emptyBlobCommit)
) )
@ -72,7 +72,7 @@ func createEmptyBlobTx(key *ecdsa.PrivateKey, withSidecar bool) *Transaction {
func createEmptyBlobTxInner(withSidecar bool) *BlobTx { func createEmptyBlobTxInner(withSidecar bool) *BlobTx {
sidecar := &BlobTxSidecar{ sidecar := &BlobTxSidecar{
Blobs: []kzg4844.Blob{emptyBlob}, Blobs: []kzg4844.Blob{*emptyBlob},
Commitments: []kzg4844.Commitment{emptyBlobCommit}, Commitments: []kzg4844.Commitment{emptyBlobCommit},
Proofs: []kzg4844.Proof{emptyBlobProof}, Proofs: []kzg4844.Proof{emptyBlobProof},
} }

View file

@ -105,7 +105,7 @@ func UseCKZG(use bool) error {
} }
// BlobToCommitment creates a small commitment out of a data blob. // BlobToCommitment creates a small commitment out of a data blob.
func BlobToCommitment(blob Blob) (Commitment, error) { func BlobToCommitment(blob *Blob) (Commitment, error) {
if useCKZG.Load() { if useCKZG.Load() {
return ckzgBlobToCommitment(blob) return ckzgBlobToCommitment(blob)
} }
@ -114,7 +114,7 @@ func BlobToCommitment(blob Blob) (Commitment, error) {
// ComputeProof computes the KZG proof at the given point for the polynomial // ComputeProof computes the KZG proof at the given point for the polynomial
// represented by the blob. // represented by the blob.
func ComputeProof(blob Blob, point Point) (Proof, Claim, error) { func ComputeProof(blob *Blob, point Point) (Proof, Claim, error) {
if useCKZG.Load() { if useCKZG.Load() {
return ckzgComputeProof(blob, point) return ckzgComputeProof(blob, point)
} }
@ -134,7 +134,7 @@ func VerifyProof(commitment Commitment, point Point, claim Claim, proof Proof) e
// the commitment. // the commitment.
// //
// This method does not verify that the commitment is correct with respect to blob. // This method does not verify that the commitment is correct with respect to blob.
func ComputeBlobProof(blob Blob, commitment Commitment) (Proof, error) { func ComputeBlobProof(blob *Blob, commitment Commitment) (Proof, error) {
if useCKZG.Load() { if useCKZG.Load() {
return ckzgComputeBlobProof(blob, commitment) return ckzgComputeBlobProof(blob, commitment)
} }
@ -142,7 +142,7 @@ func ComputeBlobProof(blob Blob, commitment Commitment) (Proof, error) {
} }
// VerifyBlobProof verifies that the blob data corresponds to the provided commitment. // VerifyBlobProof verifies that the blob data corresponds to the provided commitment.
func VerifyBlobProof(blob Blob, commitment Commitment, proof Proof) error { func VerifyBlobProof(blob *Blob, commitment Commitment, proof Proof) error {
if useCKZG.Load() { if useCKZG.Load() {
return ckzgVerifyBlobProof(blob, commitment, proof) return ckzgVerifyBlobProof(blob, commitment, proof)
} }

View file

@ -61,10 +61,10 @@ func ckzgInit() {
} }
// ckzgBlobToCommitment creates a small commitment out of a data blob. // ckzgBlobToCommitment creates a small commitment out of a data blob.
func ckzgBlobToCommitment(blob Blob) (Commitment, error) { func ckzgBlobToCommitment(blob *Blob) (Commitment, error) {
ckzgIniter.Do(ckzgInit) ckzgIniter.Do(ckzgInit)
commitment, err := ckzg4844.BlobToKZGCommitment((ckzg4844.Blob)(blob)) commitment, err := ckzg4844.BlobToKZGCommitment((*ckzg4844.Blob)(blob))
if err != nil { if err != nil {
return Commitment{}, err return Commitment{}, err
} }
@ -73,10 +73,10 @@ func ckzgBlobToCommitment(blob Blob) (Commitment, error) {
// ckzgComputeProof computes the KZG proof at the given point for the polynomial // ckzgComputeProof computes the KZG proof at the given point for the polynomial
// represented by the blob. // represented by the blob.
func ckzgComputeProof(blob Blob, point Point) (Proof, Claim, error) { func ckzgComputeProof(blob *Blob, point Point) (Proof, Claim, error) {
ckzgIniter.Do(ckzgInit) ckzgIniter.Do(ckzgInit)
proof, claim, err := ckzg4844.ComputeKZGProof((ckzg4844.Blob)(blob), (ckzg4844.Bytes32)(point)) proof, claim, err := ckzg4844.ComputeKZGProof((*ckzg4844.Blob)(blob), (ckzg4844.Bytes32)(point))
if err != nil { if err != nil {
return Proof{}, Claim{}, err return Proof{}, Claim{}, err
} }
@ -102,10 +102,10 @@ func ckzgVerifyProof(commitment Commitment, point Point, claim Claim, proof Proo
// the commitment. // the commitment.
// //
// This method does not verify that the commitment is correct with respect to blob. // This method does not verify that the commitment is correct with respect to blob.
func ckzgComputeBlobProof(blob Blob, commitment Commitment) (Proof, error) { func ckzgComputeBlobProof(blob *Blob, commitment Commitment) (Proof, error) {
ckzgIniter.Do(ckzgInit) ckzgIniter.Do(ckzgInit)
proof, err := ckzg4844.ComputeBlobKZGProof((ckzg4844.Blob)(blob), (ckzg4844.Bytes48)(commitment)) proof, err := ckzg4844.ComputeBlobKZGProof((*ckzg4844.Blob)(blob), (ckzg4844.Bytes48)(commitment))
if err != nil { if err != nil {
return Proof{}, err return Proof{}, err
} }
@ -113,10 +113,10 @@ func ckzgComputeBlobProof(blob Blob, commitment Commitment) (Proof, error) {
} }
// ckzgVerifyBlobProof verifies that the blob data corresponds to the provided commitment. // ckzgVerifyBlobProof verifies that the blob data corresponds to the provided commitment.
func ckzgVerifyBlobProof(blob Blob, commitment Commitment, proof Proof) error { func ckzgVerifyBlobProof(blob *Blob, commitment Commitment, proof Proof) error {
ckzgIniter.Do(ckzgInit) ckzgIniter.Do(ckzgInit)
valid, err := ckzg4844.VerifyBlobKZGProof((ckzg4844.Blob)(blob), (ckzg4844.Bytes48)(commitment), (ckzg4844.Bytes48)(proof)) valid, err := ckzg4844.VerifyBlobKZGProof((*ckzg4844.Blob)(blob), (ckzg4844.Bytes48)(commitment), (ckzg4844.Bytes48)(proof))
if err != nil { if err != nil {
return err return err
} }

View file

@ -32,13 +32,13 @@ func ckzgInit() {
} }
// ckzgBlobToCommitment creates a small commitment out of a data blob. // ckzgBlobToCommitment creates a small commitment out of a data blob.
func ckzgBlobToCommitment(blob Blob) (Commitment, error) { func ckzgBlobToCommitment(blob *Blob) (Commitment, error) {
panic("unsupported platform") panic("unsupported platform")
} }
// ckzgComputeProof computes the KZG proof at the given point for the polynomial // ckzgComputeProof computes the KZG proof at the given point for the polynomial
// represented by the blob. // represented by the blob.
func ckzgComputeProof(blob Blob, point Point) (Proof, Claim, error) { func ckzgComputeProof(blob *Blob, point Point) (Proof, Claim, error) {
panic("unsupported platform") panic("unsupported platform")
} }
@ -52,11 +52,11 @@ func ckzgVerifyProof(commitment Commitment, point Point, claim Claim, proof Proo
// the commitment. // the commitment.
// //
// This method does not verify that the commitment is correct with respect to blob. // This method does not verify that the commitment is correct with respect to blob.
func ckzgComputeBlobProof(blob Blob, commitment Commitment) (Proof, error) { func ckzgComputeBlobProof(blob *Blob, commitment Commitment) (Proof, error) {
panic("unsupported platform") panic("unsupported platform")
} }
// ckzgVerifyBlobProof verifies that the blob data corresponds to the provided commitment. // ckzgVerifyBlobProof verifies that the blob data corresponds to the provided commitment.
func ckzgVerifyBlobProof(blob Blob, commitment Commitment, proof Proof) error { func ckzgVerifyBlobProof(blob *Blob, commitment Commitment, proof Proof) error {
panic("unsupported platform") panic("unsupported platform")
} }

View file

@ -46,10 +46,10 @@ func gokzgInit() {
} }
// gokzgBlobToCommitment creates a small commitment out of a data blob. // gokzgBlobToCommitment creates a small commitment out of a data blob.
func gokzgBlobToCommitment(blob Blob) (Commitment, error) { func gokzgBlobToCommitment(blob *Blob) (Commitment, error) {
gokzgIniter.Do(gokzgInit) gokzgIniter.Do(gokzgInit)
commitment, err := context.BlobToKZGCommitment((gokzg4844.Blob)(blob), 0) commitment, err := context.BlobToKZGCommitment((*gokzg4844.Blob)(blob), 0)
if err != nil { if err != nil {
return Commitment{}, err return Commitment{}, err
} }
@ -58,10 +58,10 @@ func gokzgBlobToCommitment(blob Blob) (Commitment, error) {
// gokzgComputeProof computes the KZG proof at the given point for the polynomial // gokzgComputeProof computes the KZG proof at the given point for the polynomial
// represented by the blob. // represented by the blob.
func gokzgComputeProof(blob Blob, point Point) (Proof, Claim, error) { func gokzgComputeProof(blob *Blob, point Point) (Proof, Claim, error) {
gokzgIniter.Do(gokzgInit) gokzgIniter.Do(gokzgInit)
proof, claim, err := context.ComputeKZGProof((gokzg4844.Blob)(blob), (gokzg4844.Scalar)(point), 0) proof, claim, err := context.ComputeKZGProof((*gokzg4844.Blob)(blob), (gokzg4844.Scalar)(point), 0)
if err != nil { if err != nil {
return Proof{}, Claim{}, err return Proof{}, Claim{}, err
} }
@ -80,10 +80,10 @@ func gokzgVerifyProof(commitment Commitment, point Point, claim Claim, proof Pro
// the commitment. // the commitment.
// //
// This method does not verify that the commitment is correct with respect to blob. // This method does not verify that the commitment is correct with respect to blob.
func gokzgComputeBlobProof(blob Blob, commitment Commitment) (Proof, error) { func gokzgComputeBlobProof(blob *Blob, commitment Commitment) (Proof, error) {
gokzgIniter.Do(gokzgInit) gokzgIniter.Do(gokzgInit)
proof, err := context.ComputeBlobKZGProof((gokzg4844.Blob)(blob), (gokzg4844.KZGCommitment)(commitment), 0) proof, err := context.ComputeBlobKZGProof((*gokzg4844.Blob)(blob), (gokzg4844.KZGCommitment)(commitment), 0)
if err != nil { if err != nil {
return Proof{}, err return Proof{}, err
} }
@ -91,8 +91,8 @@ func gokzgComputeBlobProof(blob Blob, commitment Commitment) (Proof, error) {
} }
// gokzgVerifyBlobProof verifies that the blob data corresponds to the provided commitment. // gokzgVerifyBlobProof verifies that the blob data corresponds to the provided commitment.
func gokzgVerifyBlobProof(blob Blob, commitment Commitment, proof Proof) error { func gokzgVerifyBlobProof(blob *Blob, commitment Commitment, proof Proof) error {
gokzgIniter.Do(gokzgInit) gokzgIniter.Do(gokzgInit)
return context.VerifyBlobKZGProof((gokzg4844.Blob)(blob), (gokzg4844.KZGCommitment)(commitment), (gokzg4844.KZGProof)(proof)) return context.VerifyBlobKZGProof((*gokzg4844.Blob)(blob), (gokzg4844.KZGCommitment)(commitment), (gokzg4844.KZGProof)(proof))
} }

View file

@ -36,13 +36,13 @@ func randFieldElement() [32]byte {
return gokzg4844.SerializeScalar(r) return gokzg4844.SerializeScalar(r)
} }
func randBlob() Blob { func randBlob() *Blob {
var blob Blob var blob Blob
for i := 0; i < len(blob); i += gokzg4844.SerializedScalarSize { for i := 0; i < len(blob); i += gokzg4844.SerializedScalarSize {
fieldElementBytes := randFieldElement() fieldElementBytes := randFieldElement()
copy(blob[i:i+gokzg4844.SerializedScalarSize], fieldElementBytes[:]) copy(blob[i:i+gokzg4844.SerializedScalarSize], fieldElementBytes[:])
} }
return blob return &blob
} }
func TestCKZGWithPoint(t *testing.T) { testKZGWithPoint(t, true) } func TestCKZGWithPoint(t *testing.T) { testKZGWithPoint(t, true) }

View file

@ -628,7 +628,6 @@ func (api *API) traceBlockParallel(ctx context.Context, block *types.Block, stat
var ( var (
txs = block.Transactions() txs = block.Transactions()
blockHash = block.Hash() blockHash = block.Hash()
blockCtx = core.NewEVMBlockContext(block.Header(), api.chainContext(ctx), nil)
signer = types.MakeSigner(api.backend.ChainConfig(), block.Number(), block.Time()) signer = types.MakeSigner(api.backend.ChainConfig(), block.Number(), block.Time())
results = make([]*txTraceResult, len(txs)) results = make([]*txTraceResult, len(txs))
pend sync.WaitGroup pend sync.WaitGroup
@ -651,6 +650,11 @@ func (api *API) traceBlockParallel(ctx context.Context, block *types.Block, stat
TxIndex: task.index, TxIndex: task.index,
TxHash: txs[task.index].Hash(), TxHash: txs[task.index].Hash(),
} }
// Reconstruct the block context for each transaction
// as the GetHash function of BlockContext is not safe for
// concurrent use.
// See: https://github.com/ethereum/go-ethereum/issues/29114
blockCtx := core.NewEVMBlockContext(block.Header(), api.chainContext(ctx), nil)
res, err := api.traceTx(ctx, txs[task.index], msg, txctx, blockCtx, task.statedb, config) res, err := api.traceTx(ctx, txs[task.index], msg, txctx, blockCtx, task.statedb, config)
if err != nil { if err != nil {
results[task.index] = &txTraceResult{TxHash: txs[task.index].Hash(), Error: err.Error()} results[task.index] = &txTraceResult{TxHash: txs[task.index].Hash(), Error: err.Error()}
@ -663,6 +667,7 @@ func (api *API) traceBlockParallel(ctx context.Context, block *types.Block, stat
// Feed the transactions into the tracers and return // Feed the transactions into the tracers and return
var failed error var failed error
blockCtx := core.NewEVMBlockContext(block.Header(), api.chainContext(ctx), nil)
txloop: txloop:
for i, tx := range txs { for i, tx := range txs {
// Send the trace task over for execution // Send the trace task over for execution

4
go.mod
View file

@ -16,12 +16,12 @@ require (
github.com/cockroachdb/pebble v1.1.0 github.com/cockroachdb/pebble v1.1.0
github.com/consensys/gnark-crypto v0.12.1 github.com/consensys/gnark-crypto v0.12.1
github.com/crate-crypto/go-ipa v0.0.0-20231025140028-3c0104f4b233 github.com/crate-crypto/go-ipa v0.0.0-20231025140028-3c0104f4b233
github.com/crate-crypto/go-kzg-4844 v0.7.0 github.com/crate-crypto/go-kzg-4844 v1.0.0
github.com/davecgh/go-spew v1.1.1 github.com/davecgh/go-spew v1.1.1
github.com/deckarep/golang-set/v2 v2.1.0 github.com/deckarep/golang-set/v2 v2.1.0
github.com/donovanhide/eventsource v0.0.0-20210830082556-c59027999da0 github.com/donovanhide/eventsource v0.0.0-20210830082556-c59027999da0
github.com/dop251/goja v0.0.0-20230605162241-28ee0ee714f3 github.com/dop251/goja v0.0.0-20230605162241-28ee0ee714f3
github.com/ethereum/c-kzg-4844 v0.4.0 github.com/ethereum/c-kzg-4844 v1.0.0
github.com/fatih/color v1.13.0 github.com/fatih/color v1.13.0
github.com/ferranbt/fastssz v0.1.2 github.com/ferranbt/fastssz v0.1.2
github.com/fjl/gencodec v0.0.0-20230517082657-f9840df7b83e github.com/fjl/gencodec v0.0.0-20230517082657-f9840df7b83e

8
go.sum
View file

@ -129,8 +129,8 @@ github.com/cpuguy83/go-md2man/v2 v2.0.2 h1:p1EgwI/C7NhT0JmVkwCD2ZBK8j4aeHQX2pMHH
github.com/cpuguy83/go-md2man/v2 v2.0.2/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o= github.com/cpuguy83/go-md2man/v2 v2.0.2/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o=
github.com/crate-crypto/go-ipa v0.0.0-20231025140028-3c0104f4b233 h1:d28BXYi+wUpz1KBmiF9bWrjEMacUEREV6MBi2ODnrfQ= github.com/crate-crypto/go-ipa v0.0.0-20231025140028-3c0104f4b233 h1:d28BXYi+wUpz1KBmiF9bWrjEMacUEREV6MBi2ODnrfQ=
github.com/crate-crypto/go-ipa v0.0.0-20231025140028-3c0104f4b233/go.mod h1:geZJZH3SzKCqnz5VT0q/DyIG/tvu/dZk+VIfXicupJs= github.com/crate-crypto/go-ipa v0.0.0-20231025140028-3c0104f4b233/go.mod h1:geZJZH3SzKCqnz5VT0q/DyIG/tvu/dZk+VIfXicupJs=
github.com/crate-crypto/go-kzg-4844 v0.7.0 h1:C0vgZRk4q4EZ/JgPfzuSoxdCq3C3mOZMBShovmncxvA= github.com/crate-crypto/go-kzg-4844 v1.0.0 h1:TsSgHwrkTKecKJ4kadtHi4b3xHW5dCFUDFnUp1TsawI=
github.com/crate-crypto/go-kzg-4844 v0.7.0/go.mod h1:1kMhvPgI0Ky3yIa+9lFySEBUBXkYxeOi8ZF1sYioxhc= github.com/crate-crypto/go-kzg-4844 v1.0.0/go.mod h1:1kMhvPgI0Ky3yIa+9lFySEBUBXkYxeOi8ZF1sYioxhc=
github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E= github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E=
github.com/cyberdelia/templates v0.0.0-20141128023046-ca7fffd4298c/go.mod h1:GyV+0YP4qX0UQ7r2MoYZ+AvYDp12OF5yg4q8rGnyNh4= github.com/cyberdelia/templates v0.0.0-20141128023046-ca7fffd4298c/go.mod h1:GyV+0YP4qX0UQ7r2MoYZ+AvYDp12OF5yg4q8rGnyNh4=
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
@ -160,8 +160,8 @@ github.com/envoyproxy/go-control-plane v0.9.0/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymF
github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4=
github.com/envoyproxy/go-control-plane v0.9.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1mIlRU8Am5FuJP05cCM98= github.com/envoyproxy/go-control-plane v0.9.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1mIlRU8Am5FuJP05cCM98=
github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c= github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c=
github.com/ethereum/c-kzg-4844 v0.4.0 h1:3MS1s4JtA868KpJxroZoepdV0ZKBp3u/O5HcZ7R3nlY= github.com/ethereum/c-kzg-4844 v1.0.0 h1:0X1LBXxaEtYD9xsyj9B9ctQEZIpnvVDeoBx8aHEwTNA=
github.com/ethereum/c-kzg-4844 v0.4.0/go.mod h1:VewdlzQmpT5QSrVhbBuGoCdFJkpaJlO1aQputP83wc0= github.com/ethereum/c-kzg-4844 v1.0.0/go.mod h1:VewdlzQmpT5QSrVhbBuGoCdFJkpaJlO1aQputP83wc0=
github.com/fatih/color v1.13.0 h1:8LOYc1KYPPmyKMuN8QV2DNRWNbLo6LZ0iLs8+mlH53w= github.com/fatih/color v1.13.0 h1:8LOYc1KYPPmyKMuN8QV2DNRWNbLo6LZ0iLs8+mlH53w=
github.com/fatih/color v1.13.0/go.mod h1:kLAiJbzzSOZDVNGyDpeOxJ47H46qBXwg5ILebYFFOfk= github.com/fatih/color v1.13.0/go.mod h1:kLAiJbzzSOZDVNGyDpeOxJ47H46qBXwg5ILebYFFOfk=
github.com/ferranbt/fastssz v0.1.2 h1:Dky6dXlngF6Qjc+EfDipAkE83N5I5DE68bY6O0VLNPk= github.com/ferranbt/fastssz v0.1.2 h1:Dky6dXlngF6Qjc+EfDipAkE83N5I5DE68bY6O0VLNPk=

View file

@ -1088,7 +1088,8 @@ func TestFillBlobTransaction(t *testing.T) {
Config: params.MergedTestChainConfig, Config: params.MergedTestChainConfig,
Alloc: types.GenesisAlloc{}, Alloc: types.GenesisAlloc{},
} }
emptyBlob = kzg4844.Blob{} emptyBlob = new(kzg4844.Blob)
emptyBlobs = []kzg4844.Blob{*emptyBlob}
emptyBlobCommit, _ = kzg4844.BlobToCommitment(emptyBlob) emptyBlobCommit, _ = kzg4844.BlobToCommitment(emptyBlob)
emptyBlobProof, _ = kzg4844.ComputeBlobProof(emptyBlob, emptyBlobCommit) emptyBlobProof, _ = kzg4844.ComputeBlobProof(emptyBlob, emptyBlobCommit)
emptyBlobHash common.Hash = kzg4844.CalcBlobHashV1(sha256.New(), &emptyBlobCommit) emptyBlobHash common.Hash = kzg4844.CalcBlobHashV1(sha256.New(), &emptyBlobCommit)
@ -1171,14 +1172,14 @@ func TestFillBlobTransaction(t *testing.T) {
From: &b.acc.Address, From: &b.acc.Address,
To: &to, To: &to,
Value: (*hexutil.Big)(big.NewInt(1)), Value: (*hexutil.Big)(big.NewInt(1)),
Blobs: []kzg4844.Blob{emptyBlob}, Blobs: emptyBlobs,
Commitments: []kzg4844.Commitment{emptyBlobCommit}, Commitments: []kzg4844.Commitment{emptyBlobCommit},
Proofs: []kzg4844.Proof{emptyBlobProof}, Proofs: []kzg4844.Proof{emptyBlobProof},
}, },
want: &result{ want: &result{
Hashes: []common.Hash{emptyBlobHash}, Hashes: []common.Hash{emptyBlobHash},
Sidecar: &types.BlobTxSidecar{ Sidecar: &types.BlobTxSidecar{
Blobs: []kzg4844.Blob{emptyBlob}, Blobs: emptyBlobs,
Commitments: []kzg4844.Commitment{emptyBlobCommit}, Commitments: []kzg4844.Commitment{emptyBlobCommit},
Proofs: []kzg4844.Proof{emptyBlobProof}, Proofs: []kzg4844.Proof{emptyBlobProof},
}, },
@ -1191,14 +1192,14 @@ func TestFillBlobTransaction(t *testing.T) {
To: &to, To: &to,
Value: (*hexutil.Big)(big.NewInt(1)), Value: (*hexutil.Big)(big.NewInt(1)),
BlobHashes: []common.Hash{emptyBlobHash}, BlobHashes: []common.Hash{emptyBlobHash},
Blobs: []kzg4844.Blob{emptyBlob}, Blobs: emptyBlobs,
Commitments: []kzg4844.Commitment{emptyBlobCommit}, Commitments: []kzg4844.Commitment{emptyBlobCommit},
Proofs: []kzg4844.Proof{emptyBlobProof}, Proofs: []kzg4844.Proof{emptyBlobProof},
}, },
want: &result{ want: &result{
Hashes: []common.Hash{emptyBlobHash}, Hashes: []common.Hash{emptyBlobHash},
Sidecar: &types.BlobTxSidecar{ Sidecar: &types.BlobTxSidecar{
Blobs: []kzg4844.Blob{emptyBlob}, Blobs: emptyBlobs,
Commitments: []kzg4844.Commitment{emptyBlobCommit}, Commitments: []kzg4844.Commitment{emptyBlobCommit},
Proofs: []kzg4844.Proof{emptyBlobProof}, Proofs: []kzg4844.Proof{emptyBlobProof},
}, },
@ -1211,7 +1212,7 @@ func TestFillBlobTransaction(t *testing.T) {
To: &to, To: &to,
Value: (*hexutil.Big)(big.NewInt(1)), Value: (*hexutil.Big)(big.NewInt(1)),
BlobHashes: []common.Hash{{0x01, 0x22}}, BlobHashes: []common.Hash{{0x01, 0x22}},
Blobs: []kzg4844.Blob{emptyBlob}, Blobs: emptyBlobs,
Commitments: []kzg4844.Commitment{emptyBlobCommit}, Commitments: []kzg4844.Commitment{emptyBlobCommit},
Proofs: []kzg4844.Proof{emptyBlobProof}, Proofs: []kzg4844.Proof{emptyBlobProof},
}, },
@ -1223,12 +1224,12 @@ func TestFillBlobTransaction(t *testing.T) {
From: &b.acc.Address, From: &b.acc.Address,
To: &to, To: &to,
Value: (*hexutil.Big)(big.NewInt(1)), Value: (*hexutil.Big)(big.NewInt(1)),
Blobs: []kzg4844.Blob{emptyBlob}, Blobs: emptyBlobs,
}, },
want: &result{ want: &result{
Hashes: []common.Hash{emptyBlobHash}, Hashes: []common.Hash{emptyBlobHash},
Sidecar: &types.BlobTxSidecar{ Sidecar: &types.BlobTxSidecar{
Blobs: []kzg4844.Blob{emptyBlob}, Blobs: emptyBlobs,
Commitments: []kzg4844.Commitment{emptyBlobCommit}, Commitments: []kzg4844.Commitment{emptyBlobCommit},
Proofs: []kzg4844.Proof{emptyBlobProof}, Proofs: []kzg4844.Proof{emptyBlobProof},
}, },

View file

@ -326,12 +326,12 @@ func (args *TransactionArgs) setBlobTxSidecar(ctx context.Context, b Backend) er
commitments := make([]kzg4844.Commitment, n) commitments := make([]kzg4844.Commitment, n)
proofs := make([]kzg4844.Proof, n) proofs := make([]kzg4844.Proof, n)
for i, b := range args.Blobs { for i, b := range args.Blobs {
c, err := kzg4844.BlobToCommitment(b) c, err := kzg4844.BlobToCommitment(&b)
if err != nil { if err != nil {
return fmt.Errorf("blobs[%d]: error computing commitment: %v", i, err) return fmt.Errorf("blobs[%d]: error computing commitment: %v", i, err)
} }
commitments[i] = c commitments[i] = c
p, err := kzg4844.ComputeBlobProof(b, c) p, err := kzg4844.ComputeBlobProof(&b, c)
if err != nil { if err != nil {
return fmt.Errorf("blobs[%d]: error computing proof: %v", i, err) return fmt.Errorf("blobs[%d]: error computing proof: %v", i, err)
} }
@ -341,7 +341,7 @@ func (args *TransactionArgs) setBlobTxSidecar(ctx context.Context, b Backend) er
args.Proofs = proofs args.Proofs = proofs
} else { } else {
for i, b := range args.Blobs { for i, b := range args.Blobs {
if err := kzg4844.VerifyBlobProof(b, args.Commitments[i], args.Proofs[i]); err != nil { if err := kzg4844.VerifyBlobProof(&b, args.Commitments[i], args.Proofs[i]); err != nil {
return fmt.Errorf("failed to verify blob proof: %v", err) return fmt.Errorf("failed to verify blob proof: %v", err)
} }
} }

View file

@ -25,6 +25,7 @@ import (
mrand "math/rand" mrand "math/rand"
"net" "net"
"sync" "sync"
"sync/atomic"
"time" "time"
"github.com/ethereum/go-ethereum/common/mclock" "github.com/ethereum/go-ethereum/common/mclock"
@ -248,7 +249,7 @@ loop:
} }
case task := <-d.doneCh: case task := <-d.doneCh:
id := task.dest.ID() id := task.dest().ID()
delete(d.dialing, id) delete(d.dialing, id)
d.updateStaticPool(id) d.updateStaticPool(id)
d.doneSinceLastLog++ d.doneSinceLastLog++
@ -410,7 +411,7 @@ func (d *dialScheduler) startStaticDials(n int) (started int) {
// updateStaticPool attempts to move the given static dial back into staticPool. // updateStaticPool attempts to move the given static dial back into staticPool.
func (d *dialScheduler) updateStaticPool(id enode.ID) { func (d *dialScheduler) updateStaticPool(id enode.ID) {
task, ok := d.static[id] task, ok := d.static[id]
if ok && task.staticPoolIndex < 0 && d.checkDial(task.dest) == nil { if ok && task.staticPoolIndex < 0 && d.checkDial(task.dest()) == nil {
d.addToStaticPool(task) d.addToStaticPool(task)
} }
} }
@ -437,10 +438,11 @@ func (d *dialScheduler) removeFromStaticPool(idx int) {
// startDial runs the given dial task in a separate goroutine. // startDial runs the given dial task in a separate goroutine.
func (d *dialScheduler) startDial(task *dialTask) { func (d *dialScheduler) startDial(task *dialTask) {
d.log.Trace("Starting p2p dial", "id", task.dest.ID(), "ip", task.dest.IP(), "flag", task.flags) node := task.dest()
hkey := string(task.dest.ID().Bytes()) d.log.Trace("Starting p2p dial", "id", node.ID(), "ip", node.IP(), "flag", task.flags)
hkey := string(node.ID().Bytes())
d.history.add(hkey, d.clock.Now().Add(dialHistoryExpiration)) d.history.add(hkey, d.clock.Now().Add(dialHistoryExpiration))
d.dialing[task.dest.ID()] = task d.dialing[node.ID()] = task
go func() { go func() {
task.run(d) task.run(d)
d.doneCh <- task d.doneCh <- task
@ -451,39 +453,46 @@ func (d *dialScheduler) startDial(task *dialTask) {
type dialTask struct { type dialTask struct {
staticPoolIndex int staticPoolIndex int
flags connFlag flags connFlag
// These fields are private to the task and should not be // These fields are private to the task and should not be
// accessed by dialScheduler while the task is running. // accessed by dialScheduler while the task is running.
dest *enode.Node destPtr atomic.Pointer[enode.Node]
lastResolved mclock.AbsTime lastResolved mclock.AbsTime
resolveDelay time.Duration resolveDelay time.Duration
} }
func newDialTask(dest *enode.Node, flags connFlag) *dialTask { func newDialTask(dest *enode.Node, flags connFlag) *dialTask {
return &dialTask{dest: dest, flags: flags, staticPoolIndex: -1} t := &dialTask{flags: flags, staticPoolIndex: -1}
t.destPtr.Store(dest)
return t
} }
type dialError struct { type dialError struct {
error error
} }
func (t *dialTask) dest() *enode.Node {
return t.destPtr.Load()
}
func (t *dialTask) run(d *dialScheduler) { func (t *dialTask) run(d *dialScheduler) {
if t.needResolve() && !t.resolve(d) { if t.needResolve() && !t.resolve(d) {
return return
} }
err := t.dial(d, t.dest) err := t.dial(d, t.dest())
if err != nil { if err != nil {
// For static nodes, resolve one more time if dialing fails. // For static nodes, resolve one more time if dialing fails.
if _, ok := err.(*dialError); ok && t.flags&staticDialedConn != 0 { if _, ok := err.(*dialError); ok && t.flags&staticDialedConn != 0 {
if t.resolve(d) { if t.resolve(d) {
t.dial(d, t.dest) t.dial(d, t.dest())
} }
} }
} }
} }
func (t *dialTask) needResolve() bool { func (t *dialTask) needResolve() bool {
return t.flags&staticDialedConn != 0 && t.dest.IP() == nil return t.flags&staticDialedConn != 0 && t.dest().IP() == nil
} }
// resolve attempts to find the current endpoint for the destination // resolve attempts to find the current endpoint for the destination
@ -502,29 +511,31 @@ func (t *dialTask) resolve(d *dialScheduler) bool {
if t.lastResolved > 0 && time.Duration(d.clock.Now()-t.lastResolved) < t.resolveDelay { if t.lastResolved > 0 && time.Duration(d.clock.Now()-t.lastResolved) < t.resolveDelay {
return false return false
} }
resolved := d.resolver.Resolve(t.dest)
node := t.dest()
resolved := d.resolver.Resolve(node)
t.lastResolved = d.clock.Now() t.lastResolved = d.clock.Now()
if resolved == nil { if resolved == nil {
t.resolveDelay *= 2 t.resolveDelay *= 2
if t.resolveDelay > maxResolveDelay { if t.resolveDelay > maxResolveDelay {
t.resolveDelay = maxResolveDelay t.resolveDelay = maxResolveDelay
} }
d.log.Debug("Resolving node failed", "id", t.dest.ID(), "newdelay", t.resolveDelay) d.log.Debug("Resolving node failed", "id", node.ID(), "newdelay", t.resolveDelay)
return false return false
} }
// The node was found. // The node was found.
t.resolveDelay = initialResolveDelay t.resolveDelay = initialResolveDelay
t.dest = resolved t.destPtr.Store(resolved)
d.log.Debug("Resolved node", "id", t.dest.ID(), "addr", &net.TCPAddr{IP: t.dest.IP(), Port: t.dest.TCP()}) d.log.Debug("Resolved node", "id", resolved.ID(), "addr", &net.TCPAddr{IP: resolved.IP(), Port: resolved.TCP()})
return true return true
} }
// dial performs the actual connection attempt. // dial performs the actual connection attempt.
func (t *dialTask) dial(d *dialScheduler, dest *enode.Node) error { func (t *dialTask) dial(d *dialScheduler, dest *enode.Node) error {
dialMeter.Mark(1) dialMeter.Mark(1)
fd, err := d.dialer.Dial(d.ctx, t.dest) fd, err := d.dialer.Dial(d.ctx, dest)
if err != nil { if err != nil {
d.log.Trace("Dial error", "id", t.dest.ID(), "addr", nodeAddr(t.dest), "conn", t.flags, "err", cleanupDialErr(err)) d.log.Trace("Dial error", "id", dest.ID(), "addr", nodeAddr(dest), "conn", t.flags, "err", cleanupDialErr(err))
dialConnectionError.Mark(1) dialConnectionError.Mark(1)
return &dialError{err} return &dialError{err}
} }
@ -532,8 +543,9 @@ func (t *dialTask) dial(d *dialScheduler, dest *enode.Node) error {
} }
func (t *dialTask) String() string { func (t *dialTask) String() string {
id := t.dest.ID() node := t.dest()
return fmt.Sprintf("%v %x %v:%d", t.flags, id[:8], t.dest.IP(), t.dest.TCP()) id := node.ID()
return fmt.Sprintf("%v %x %v:%d", t.flags, id[:8], node.IP(), node.TCP())
} }
func cleanupDialErr(err error) error { func cleanupDialErr(err error) error {