From 7a65be6c1abfa26f0b91923f98db6d4455fae1bd Mon Sep 17 00:00:00 2001 From: Andrew Ashikhmin <34320705+yperbasis@users.noreply.github.com> Date: Thu, 24 Oct 2024 15:13:47 +0200 Subject: [PATCH] Block: use generic atomics (#12461) Cherry pick #11512 into `release/2.61` Co-authored-by: Alex Sharov --- cmd/evm/internal/t8ntool/transition.go | 12 ++++-- core/types/access_list_tx.go | 20 +++------- core/types/blob_tx.go | 11 +++--- core/types/blob_tx_wrapper.go | 9 +---- core/types/block.go | 54 ++++++++++++-------------- core/types/dynamic_fee_tx.go | 21 +++------- core/types/encdec_test.go | 10 ++--- core/types/legacy_tx.go | 26 ++++--------- core/types/set_code_tx.go | 16 ++------ core/types/transaction.go | 5 +-- core/types/transaction_marshalling.go | 8 ++-- core/types/transaction_test.go | 4 +- 12 files changed, 73 insertions(+), 123 deletions(-) diff --git a/cmd/evm/internal/t8ntool/transition.go b/cmd/evm/internal/t8ntool/transition.go index 9ff2e2041c2..72efbbd2c17 100644 --- a/cmd/evm/internal/t8ntool/transition.go +++ b/cmd/evm/internal/t8ntool/transition.go @@ -423,7 +423,8 @@ func getTransaction(txJson jsonrpc.RPCTransaction) (types.Transaction, error) { commonTx.S.SetFromBig(txJson.S.ToInt()) if txJson.Type == types.LegacyTxType || txJson.Type == types.AccessListTxType { legacyTx := types.LegacyTx{ - CommonTx: commonTx, + //it's ok to copy here - because it's constructor of object - no parallel access yet + CommonTx: commonTx, //nolint GasPrice: gasPrice, } @@ -432,7 +433,8 @@ func getTransaction(txJson jsonrpc.RPCTransaction) (types.Transaction, error) { } return &types.AccessListTx{ - LegacyTx: legacyTx, + //it's ok to copy here - because it's constructor of object - no parallel access yet + LegacyTx: legacyTx, //nolint ChainID: chainId, AccessList: *txJson.Accesses, }, nil @@ -454,7 +456,8 @@ func getTransaction(txJson jsonrpc.RPCTransaction) (types.Transaction, error) { } dynamicFeeTx := types.DynamicFeeTransaction{ - CommonTx: commonTx, + //it's ok to copy here - because it's constructor of object - no parallel access yet + CommonTx: commonTx, //nolint ChainID: chainId, Tip: tip, FeeCap: feeCap, @@ -471,7 +474,8 @@ func getTransaction(txJson jsonrpc.RPCTransaction) (types.Transaction, error) { } return &types.SetCodeTransaction{ - DynamicFeeTransaction: dynamicFeeTx, + // it's ok to copy here - because it's constructor of object - no parallel access yet + DynamicFeeTransaction: dynamicFeeTx, //nolint Authorizations: auths, }, nil } else { diff --git a/core/types/access_list_tx.go b/core/types/access_list_tx.go index 2324e0d0636..5746910f9d9 100644 --- a/core/types/access_list_tx.go +++ b/core/types/access_list_tx.go @@ -31,7 +31,6 @@ import ( rlp2 "github.com/ledgerwatch/erigon-lib/rlp" types2 "github.com/ledgerwatch/erigon-lib/types" - "github.com/ledgerwatch/erigon/common/u256" "github.com/ledgerwatch/erigon/rlp" ) @@ -446,19 +445,11 @@ func (tx *AccessListTx) WithSignature(signer Signer, sig []byte) (Transaction, e cpy.ChainID = signer.ChainID() return cpy, nil } -func (tx *AccessListTx) FakeSign(address libcommon.Address) Transaction { - cpy := tx.copy() - cpy.R.Set(u256.Num1) - cpy.S.Set(u256.Num1) - cpy.V.Set(u256.Num4) - cpy.from.Store(address) - return cpy -} // Hash computes the hash (but not for signatures!) func (tx *AccessListTx) Hash() libcommon.Hash { if hash := tx.hash.Load(); hash != nil { - return *hash.(*libcommon.Hash) + return *hash } hash := prefixedRlpHash(AccessListTxType, []interface{}{ tx.ChainID, @@ -503,15 +494,16 @@ func (tx *AccessListTx) GetChainID() *uint256.Int { var zeroAddr = libcommon.Address{} func (tx *AccessListTx) Sender(signer Signer) (libcommon.Address, error) { - if sc := tx.from.Load(); sc != nil { - if sc.(libcommon.Address) != zeroAddr { // Sender address can never be zero in a transaction with a valid signer - return sc.(libcommon.Address), nil + if from := tx.from.Load(); from != nil { + if *from != zeroAddr { // Sender address can never be zero in a transaction with a valid signer + return *from, nil } } + addr, err := signer.Sender(tx) if err != nil { return libcommon.Address{}, err } - tx.from.Store(addr) + tx.from.Store(&addr) return addr, nil } diff --git a/core/types/blob_tx.go b/core/types/blob_tx.go index cdda3ea7ef3..fd715230a7e 100644 --- a/core/types/blob_tx.go +++ b/core/types/blob_tx.go @@ -81,23 +81,22 @@ func (stx *BlobTx) AsMessage(s Signer, baseFee *big.Int, rules *chain.Rules) (Me } func (stx *BlobTx) Sender(signer Signer) (libcommon.Address, error) { - if sc := stx.from.Load(); sc != nil { - zeroAddr := libcommon.Address{} - if sc.(libcommon.Address) != zeroAddr { // Sender address can never be zero in a transaction with a valid signer - return sc.(libcommon.Address), nil + if from := stx.from.Load(); from != nil { + if *from != zeroAddr { // Sender address can never be zero in a transaction with a valid signer + return *from, nil } } addr, err := signer.Sender(stx) if err != nil { return libcommon.Address{}, err } - stx.from.Store(addr) + stx.from.Store(&addr) return addr, nil } func (stx *BlobTx) Hash() libcommon.Hash { if hash := stx.hash.Load(); hash != nil { - return *hash.(*libcommon.Hash) + return *hash } hash := prefixedRlpHash(BlobTxType, []interface{}{ stx.ChainID, diff --git a/core/types/blob_tx_wrapper.go b/core/types/blob_tx_wrapper.go index 996107bb8e2..93f11bec775 100644 --- a/core/types/blob_tx_wrapper.go +++ b/core/types/blob_tx_wrapper.go @@ -256,8 +256,7 @@ func (c KZGCommitment) ComputeVersionedHash() libcommon.Hash { // validateBlobTransactionWrapper implements validate_blob_transaction_wrapper from EIP-4844 func (txw *BlobTxWrapper) ValidateBlobTransactionWrapper() error { - blobTx := txw.Tx - l1 := len(blobTx.BlobVersionedHashes) + l1 := len(txw.Tx.BlobVersionedHashes) if l1 == 0 { return fmt.Errorf("a blob tx must contain at least one blob") } @@ -278,7 +277,7 @@ func (txw *BlobTxWrapper) ValidateBlobTransactionWrapper() error { if err != nil { return fmt.Errorf("error during proof verification: %v", err) } - for i, h := range blobTx.BlobVersionedHashes { + for i, h := range txw.Tx.BlobVersionedHashes { if computed := txw.Commitments[i].ComputeVersionedHash(); computed != h { return fmt.Errorf("versioned hash %d supposedly %s but does not match computed %s", i, h, computed) } @@ -311,10 +310,6 @@ func (txw *BlobTxWrapper) WithSignature(signer Signer, sig []byte) (Transaction, return txw.Tx.WithSignature(signer, sig) } -func (txw *BlobTxWrapper) FakeSign(address libcommon.Address) Transaction { - return txw.Tx.FakeSign(address) -} - func (txw *BlobTxWrapper) Hash() libcommon.Hash { return txw.Tx.Hash() } func (txw *BlobTxWrapper) SigningHash(chainID *big.Int) libcommon.Hash { diff --git a/core/types/block.go b/core/types/block.go index a3aabf87c71..766094bd50f 100644 --- a/core/types/block.go +++ b/core/types/block.go @@ -681,8 +681,8 @@ type Block struct { requests Requests // caches - hash atomic.Value - size atomic.Value + hash atomic.Pointer[libcommon.Hash] + size atomic.Uint64 } // Copy transaction senders from body into the transactions @@ -1062,7 +1062,7 @@ func NewBlock(header *Header, txs []Transaction, uncles []*Header, receipts []*R // in this case no reason to copy parts, or re-calculate headers fields - they are all stored in DB func NewBlockFromStorage(hash libcommon.Hash, header *Header, txs []Transaction, uncles []*Header, withdrawals []*Withdrawal, requests Requests) *Block { b := &Block{header: header, transactions: txs, uncles: uncles, withdrawals: withdrawals, requests: requests} - b.hash.Store(hash) + b.hash.Store(&hash) return b } @@ -1136,7 +1136,7 @@ func (bb *Block) DecodeRLP(s *rlp.Stream) error { if err != nil { return err } - bb.size.Store(common.StorageSize(rlp.ListSize(size))) + bb.size.Store(rlp.ListSize(size)) // decode header var h Header @@ -1166,7 +1166,7 @@ func (bb *Block) DecodeRLP(s *rlp.Stream) error { return s.ListEnd() } -func (bb Block) payloadSize() (payloadSize int, txsLen, unclesLen, withdrawalsLen, requestsLen int) { +func (bb *Block) payloadSize() (payloadSize int, txsLen, unclesLen, withdrawalsLen, requestsLen int) { // size of Header headerLen := bb.header.EncodingSize() payloadSize += rlp2.ListPrefixLen(headerLen) + headerLen @@ -1195,13 +1195,13 @@ func (bb Block) payloadSize() (payloadSize int, txsLen, unclesLen, withdrawalsLe return payloadSize, txsLen, unclesLen, withdrawalsLen, requestsLen } -func (bb Block) EncodingSize() int { +func (bb *Block) EncodingSize() int { payloadSize, _, _, _, _ := bb.payloadSize() return payloadSize } // EncodeRLP serializes b into the Ethereum RLP block format. -func (bb Block) EncodeRLP(w io.Writer) error { +func (bb *Block) EncodeRLP(w io.Writer) error { payloadSize, txsLen, unclesLen, withdrawalsLen, _ /* requestsLen */ := bb.payloadSize() var b [33]byte // prefix @@ -1324,12 +1324,12 @@ func (b *Body) RawBody() *RawBody { // Size returns the true RLP encoded storage size of the block, either by encoding // and returning it, or returning a previously cached value. func (b *Block) Size() common.StorageSize { - if size := b.size.Load(); size != nil { - return size.(common.StorageSize) + if size := b.size.Load(); size > 0 { + return common.StorageSize(size) } c := writeCounter(0) rlp.Encode(&c, b) - b.size.Store(common.StorageSize(c)) + b.size.Store(uint64(c)) return common.StorageSize(c) } @@ -1412,7 +1412,8 @@ func CopyTxs(in Transactions) Transactions { if txWrapper, ok := tx.(*BlobTxWrapper); ok { blobTx := out[i].(*BlobTx) out[i] = &BlobTxWrapper{ - Tx: *blobTx, + // it's ok to copy here - because it's constructor of object - no parallel access yet + Tx: *blobTx, //nolint Commitments: txWrapper.Commitments.copy(), Blobs: txWrapper.Blobs.copy(), Proofs: txWrapper.Proofs.copy(), @@ -1446,27 +1447,20 @@ func (b *Block) Copy() *Block { } } - var hashValue atomic.Value - if value := b.hash.Load(); value != nil { - hash := value.(libcommon.Hash) - hashCopy := libcommon.BytesToHash(hash.Bytes()) - hashValue.Store(hashCopy) - } - - var sizeValue atomic.Value - if size := b.size.Load(); size != nil { - sizeValue.Store(size) - } - - return &Block{ + newB := &Block{ header: CopyHeader(b.header), uncles: uncles, transactions: CopyTxs(b.transactions), withdrawals: withdrawals, requests: requests, - hash: hashValue, - size: sizeValue, } + if h := b.hash.Load(); h != nil { + hashCopy := *h + newB.hash.Store(&hashCopy) + } + szCopy := b.size.Load() + newB.size.Store(szCopy) + return newB } // WithSeal returns a new block with the data from b but the header replaced with @@ -1487,11 +1481,11 @@ func (b *Block) WithSeal(header *Header) *Block { // The hash is computed on the first call and cached thereafter. func (b *Block) Hash() libcommon.Hash { if hash := b.hash.Load(); hash != nil { - return hash.(libcommon.Hash) + return *hash } - v := b.header.Hash() - b.hash.Store(v) - return v + h := b.header.Hash() + b.hash.Store(&h) + return h } type Blocks []*Block diff --git a/core/types/dynamic_fee_tx.go b/core/types/dynamic_fee_tx.go index a567f46f9da..7e92999fc3f 100644 --- a/core/types/dynamic_fee_tx.go +++ b/core/types/dynamic_fee_tx.go @@ -29,7 +29,6 @@ import ( rlp2 "github.com/ledgerwatch/erigon-lib/rlp" types2 "github.com/ledgerwatch/erigon-lib/types" - "github.com/ledgerwatch/erigon/common/u256" "github.com/ledgerwatch/erigon/rlp" ) @@ -167,15 +166,6 @@ func (tx *DynamicFeeTransaction) WithSignature(signer Signer, sig []byte) (Trans return cpy, nil } -func (tx *DynamicFeeTransaction) FakeSign(address libcommon.Address) Transaction { - cpy := tx.copy() - cpy.R.Set(u256.Num1) - cpy.S.Set(u256.Num1) - cpy.V.Set(u256.Num4) - cpy.from.Store(address) - return cpy -} - // MarshalBinary returns the canonical encoding of the transaction. // For legacy transactions, it returns the RLP encoding. For EIP-2718 typed // transactions, it returns the type and payload. @@ -371,7 +361,7 @@ func (tx *DynamicFeeTransaction) AsMessage(s Signer, baseFee *big.Int, rules *ch // Hash computes the hash (but not for signatures!) func (tx *DynamicFeeTransaction) Hash() libcommon.Hash { if hash := tx.hash.Load(); hash != nil { - return *hash.(*libcommon.Hash) + return *hash } hash := prefixedRlpHash(DynamicFeeTxType, []interface{}{ tx.ChainID, @@ -417,17 +407,16 @@ func (tx *DynamicFeeTransaction) GetChainID() *uint256.Int { } func (tx *DynamicFeeTransaction) Sender(signer Signer) (libcommon.Address, error) { - if sc := tx.from.Load(); sc != nil { - zeroAddr := libcommon.Address{} - if sc.(libcommon.Address) != zeroAddr { // Sender address can never be zero in a transaction with a valid signer - return sc.(libcommon.Address), nil + if from := tx.from.Load(); from != nil { + if *from != zeroAddr { // Sender address can never be zero in a transaction with a valid signer + return *from, nil } } addr, err := signer.Sender(tx) if err != nil { return libcommon.Address{}, err } - tx.from.Store(addr) + tx.from.Store(&addr) return addr, nil } diff --git a/core/types/encdec_test.go b/core/types/encdec_test.go index a06e66cad20..ea918fbb57b 100644 --- a/core/types/encdec_test.go +++ b/core/types/encdec_test.go @@ -183,13 +183,13 @@ func (tr *TRand) RandTransaction() Transaction { switch txType { case LegacyTxType: return &LegacyTx{ - CommonTx: commonTx, + CommonTx: commonTx, //nolint GasPrice: uint256.NewInt(*tr.RandUint64()), } case AccessListTxType: return &AccessListTx{ LegacyTx: LegacyTx{ - CommonTx: commonTx, + CommonTx: commonTx, //nolint GasPrice: uint256.NewInt(*tr.RandUint64()), }, ChainID: uint256.NewInt(*tr.RandUint64()), @@ -197,7 +197,7 @@ func (tr *TRand) RandTransaction() Transaction { } case DynamicFeeTxType: return &DynamicFeeTransaction{ - CommonTx: commonTx, + CommonTx: commonTx, //nolint ChainID: uint256.NewInt(*tr.RandUint64()), Tip: uint256.NewInt(*tr.RandUint64()), FeeCap: uint256.NewInt(*tr.RandUint64()), @@ -207,7 +207,7 @@ func (tr *TRand) RandTransaction() Transaction { r := *tr.RandUint64() return &BlobTx{ DynamicFeeTransaction: DynamicFeeTransaction{ - CommonTx: commonTx, + CommonTx: commonTx, //nolint ChainID: uint256.NewInt(*tr.RandUint64()), Tip: uint256.NewInt(*tr.RandUint64()), FeeCap: uint256.NewInt(*tr.RandUint64()), @@ -219,7 +219,7 @@ func (tr *TRand) RandTransaction() Transaction { case SetCodeTxType: return &SetCodeTransaction{ DynamicFeeTransaction: DynamicFeeTransaction{ - CommonTx: commonTx, + CommonTx: commonTx, //nolint ChainID: uint256.NewInt(*tr.RandUint64()), Tip: uint256.NewInt(*tr.RandUint64()), FeeCap: uint256.NewInt(*tr.RandUint64()), diff --git a/core/types/legacy_tx.go b/core/types/legacy_tx.go index b0682191720..4a28719791b 100644 --- a/core/types/legacy_tx.go +++ b/core/types/legacy_tx.go @@ -28,7 +28,6 @@ import ( rlp2 "github.com/ledgerwatch/erigon-lib/rlp" types2 "github.com/ledgerwatch/erigon-lib/types" - "github.com/ledgerwatch/erigon/common/u256" "github.com/ledgerwatch/erigon/rlp" ) @@ -69,13 +68,13 @@ func (ct *CommonTx) GetData() []byte { func (ct *CommonTx) GetSender() (libcommon.Address, bool) { if sc := ct.from.Load(); sc != nil { - return sc.(libcommon.Address), true + return *sc, true } return libcommon.Address{}, false } func (ct *CommonTx) SetSender(addr libcommon.Address) { - ct.from.Store(addr) + ct.from.Store(&addr) } func (ct *CommonTx) Protected() bool { @@ -372,19 +371,10 @@ func (tx *LegacyTx) WithSignature(signer Signer, sig []byte) (Transaction, error return cpy, nil } -func (tx *LegacyTx) FakeSign(address libcommon.Address) Transaction { - cpy := tx.copy() - cpy.R.Set(u256.Num1) - cpy.S.Set(u256.Num1) - cpy.V.Set(u256.Num4) - cpy.from.Store(address) - return cpy -} - // Hash computes the hash (but not for signatures!) func (tx *LegacyTx) Hash() libcommon.Hash { if hash := tx.hash.Load(); hash != nil { - return *hash.(*libcommon.Hash) + return *hash } hash := rlpHash([]interface{}{ tx.Nonce, @@ -432,16 +422,16 @@ func (tx *LegacyTx) GetChainID() *uint256.Int { } func (tx *LegacyTx) Sender(signer Signer) (libcommon.Address, error) { - if sc := tx.from.Load(); sc != nil { - zeroAddr := libcommon.Address{} - if sc.(libcommon.Address) != zeroAddr { // Sender address can never be zero in a transaction with a valid signer - return sc.(libcommon.Address), nil + if from := tx.from.Load(); from != nil { + if *from != zeroAddr { // Sender address can never be zero in a transaction with a valid signer + return *from, nil } } + addr, err := signer.Sender(tx) if err != nil { return libcommon.Address{}, err } - tx.from.Store(addr) + tx.from.Store(&addr) return addr, nil } diff --git a/core/types/set_code_tx.go b/core/types/set_code_tx.go index 60544f1fa58..7d4c92d3995 100644 --- a/core/types/set_code_tx.go +++ b/core/types/set_code_tx.go @@ -12,7 +12,6 @@ import ( libcommon "github.com/ledgerwatch/erigon-lib/common" rlp2 "github.com/ledgerwatch/erigon-lib/rlp" types2 "github.com/ledgerwatch/erigon-lib/types" - "github.com/ledgerwatch/erigon/common/u256" "github.com/ledgerwatch/erigon/params" "github.com/ledgerwatch/erigon/rlp" ) @@ -82,15 +81,6 @@ func (tx *SetCodeTransaction) WithSignature(signer Signer, sig []byte) (Transact return cpy, nil } -func (tx *SetCodeTransaction) FakeSign(address libcommon.Address) Transaction { - cpy := tx.copy() - cpy.R.Set(u256.Num1) - cpy.S.Set(u256.Num1) - cpy.V.Set(u256.Num4) - cpy.from.Store(address) - return cpy -} - func (tx *SetCodeTransaction) MarshalBinary(w io.Writer) error { payloadSize, nonceLen, gasLen, accessListLen, authorizationsLen := tx.payloadSize() var b [33]byte @@ -144,8 +134,8 @@ func (tx *SetCodeTransaction) AsMessage(s Signer, baseFee *big.Int, rules *chain func (tx *SetCodeTransaction) Sender(signer Signer) (libcommon.Address, error) { if from := tx.from.Load(); from != nil { - if from.(libcommon.Address) != zeroAddr { // Sender address can never be zero in a transaction with a valid signer - return from.(libcommon.Address), nil + if *from != zeroAddr { // Sender address can never be zero in a transaction with a valid signer + return *from, nil } } addr, err := signer.Sender(tx) @@ -158,7 +148,7 @@ func (tx *SetCodeTransaction) Sender(signer Signer) (libcommon.Address, error) { func (tx *SetCodeTransaction) Hash() libcommon.Hash { if hash := tx.hash.Load(); hash != nil { - return *hash.(*libcommon.Hash) + return *hash } hash := prefixedRlpHash(SetCodeTxType, []interface{}{ tx.ChainID, diff --git a/core/types/transaction.go b/core/types/transaction.go index 2a3e279defc..4691da29a6d 100644 --- a/core/types/transaction.go +++ b/core/types/transaction.go @@ -70,7 +70,6 @@ type Transaction interface { GetTo() *libcommon.Address AsMessage(s Signer, baseFee *big.Int, rules *chain.Rules) (Message, error) WithSignature(signer Signer, sig []byte) (Transaction, error) - FakeSign(address libcommon.Address) Transaction Hash() libcommon.Hash SigningHash(chainID *big.Int) libcommon.Hash GetData() []byte @@ -99,8 +98,8 @@ type Transaction interface { // implementations of different transaction types type TransactionMisc struct { // caches - hash atomic.Value //nolint:structcheck - from atomic.Value + hash atomic.Pointer[libcommon.Hash] + from atomic.Pointer[libcommon.Address] } // RLP-marshalled legacy transactions and binary-marshalled (not wrapped into an RLP string) typed (EIP-2718) transactions diff --git a/core/types/transaction_marshalling.go b/core/types/transaction_marshalling.go index 714c5dbfaaa..e119a567ec4 100644 --- a/core/types/transaction_marshalling.go +++ b/core/types/transaction_marshalling.go @@ -466,12 +466,9 @@ func (tx *SetCodeTransaction) UnmarshalJSON(input []byte) error { return err } - dTx := DynamicFeeTransaction{} - if err := dTx.unmarshalJson(dec); err != nil { + if err := tx.DynamicFeeTransaction.unmarshalJson(dec); err != nil { return err } - - tx.DynamicFeeTransaction = dTx tx.Authorizations = make([]Authorization, len(*dec.Authorizations)) for i, auth := range *dec.Authorizations { tx.Authorizations[i] = auth.ToAuthorization() @@ -580,7 +577,8 @@ func UnmarshalBlobTxJSON(input []byte) (Transaction, error) { } btx := BlobTxWrapper{ - Tx: tx, + // it's ok to copy here - because it's constructor of object - no parallel access yet + Tx: tx, //nolint Commitments: dec.Commitments, Blobs: dec.Blobs, Proofs: dec.Proofs, diff --git a/core/types/transaction_test.go b/core/types/transaction_test.go index 669389e635a..141394978e2 100644 --- a/core/types/transaction_test.go +++ b/core/types/transaction_test.go @@ -690,10 +690,10 @@ func newRandBlobs(size int) Blobs { } func newRandBlobWrapper() *BlobTxWrapper { - btxw := *newRandBlobTx() + btxw := newRandBlobTx() l := len(btxw.BlobVersionedHashes) return &BlobTxWrapper{ - Tx: btxw, + Tx: *btxw, //nolint Commitments: newRandCommitments(l), Blobs: newRandBlobs(l), Proofs: newRandProofs(l),