From 9b0898121de1891c4dbf1fac1df34b23cd474ee1 Mon Sep 17 00:00:00 2001 From: Alex Sharov Date: Thu, 8 Aug 2024 08:03:03 +0700 Subject: [PATCH] Block: use generic atomics (#11512) --- cmd/evm/internal/t8ntool/transition.go | 12 ++++-- core/types/access_list_tx.go | 26 +++++-------- core/types/blob_tx.go | 13 +++---- core/types/blob_tx_wrapper.go | 9 +---- core/types/block.go | 54 ++++++++++++-------------- core/types/dynamic_fee_tx.go | 23 +++-------- core/types/encdec_test.go | 10 ++--- core/types/legacy_tx.go | 28 +++++-------- core/types/set_code_tx.go | 12 +----- core/types/transaction.go | 5 +-- core/types/transaction_marshalling.go | 8 ++-- core/types/transaction_test.go | 4 +- 12 files changed, 78 insertions(+), 126 deletions(-) diff --git a/cmd/evm/internal/t8ntool/transition.go b/cmd/evm/internal/t8ntool/transition.go index 1a0d89647e2..2a259960ef9 100644 --- a/cmd/evm/internal/t8ntool/transition.go +++ b/cmd/evm/internal/t8ntool/transition.go @@ -429,7 +429,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, } @@ -438,7 +439,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 @@ -460,7 +462,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, @@ -477,7 +480,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 a14873353de..90f54aebeff 100644 --- a/core/types/access_list_tx.go +++ b/core/types/access_list_tx.go @@ -34,7 +34,6 @@ import ( rlp2 "github.com/erigontech/erigon-lib/rlp" types2 "github.com/erigontech/erigon-lib/types" - "github.com/erigontech/erigon/common/u256" "github.com/erigontech/erigon/rlp" ) @@ -449,19 +448,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, @@ -508,19 +499,22 @@ func (tx *AccessListTx) cachedSender() (sender libcommon.Address, ok bool) { if s == nil { return sender, false } - return s.(libcommon.Address), true + return *s, true } + +var zeroAddr = libcommon.Address{} + func (tx *AccessListTx) 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/blob_tx.go b/core/types/blob_tx.go index a2f4f78a660..57f1c23c2d4 100644 --- a/core/types/blob_tx.go +++ b/core/types/blob_tx.go @@ -101,27 +101,26 @@ func (stx *BlobTx) cachedSender() (sender libcommon.Address, ok bool) { if s == nil { return sender, false } - return s.(libcommon.Address), true + return *s, true } 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 0a914c065f1..89454389272 100644 --- a/core/types/blob_tx_wrapper.go +++ b/core/types/blob_tx_wrapper.go @@ -273,8 +273,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 errors.New("a blob txn must contain at least one blob") } @@ -295,7 +294,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) } @@ -328,10 +327,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 d379550f274..5c01392674e 100644 --- a/core/types/block.go +++ b/core/types/block.go @@ -719,8 +719,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 @@ -1100,7 +1100,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 } @@ -1174,7 +1174,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 @@ -1204,7 +1204,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 @@ -1233,13 +1233,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 @@ -1362,12 +1362,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) } @@ -1450,7 +1450,8 @@ func CopyTxs(in Transactions) Transactions { if txWrapper, ok := txn.(*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(), @@ -1484,27 +1485,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 @@ -1525,11 +1519,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 38b787bd7e6..31d4d4799e9 100644 --- a/core/types/dynamic_fee_tx.go +++ b/core/types/dynamic_fee_tx.go @@ -32,7 +32,6 @@ import ( rlp2 "github.com/erigontech/erigon-lib/rlp" types2 "github.com/erigontech/erigon-lib/types" - "github.com/erigontech/erigon/common/u256" "github.com/erigontech/erigon/rlp" ) @@ -170,15 +169,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. @@ -374,7 +364,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, @@ -424,20 +414,19 @@ func (tx *DynamicFeeTransaction) cachedSender() (sender libcommon.Address, ok bo if s == nil { return sender, false } - return s.(libcommon.Address), true + return *s, true } 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 2270a81921a..c6f1559176a 100644 --- a/core/types/encdec_test.go +++ b/core/types/encdec_test.go @@ -208,13 +208,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()), @@ -222,7 +222,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()), @@ -232,7 +232,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()), @@ -244,7 +244,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 b44e9c2df8e..8a3fe25b68d 100644 --- a/core/types/legacy_tx.go +++ b/core/types/legacy_tx.go @@ -32,7 +32,6 @@ import ( rlp2 "github.com/erigontech/erigon-lib/rlp" types2 "github.com/erigontech/erigon-lib/types" - "github.com/erigontech/erigon/common/u256" "github.com/erigontech/erigon/rlp" ) @@ -73,13 +72,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 { @@ -376,19 +375,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, @@ -440,19 +430,19 @@ func (tx *LegacyTx) cachedSender() (sender libcommon.Address, ok bool) { if s == nil { return sender, false } - return s.(libcommon.Address), true + return *s, true } 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 aeb0f71d10a..f725dcf4886 100644 --- a/core/types/set_code_tx.go +++ b/core/types/set_code_tx.go @@ -12,7 +12,6 @@ import ( libcommon "github.com/erigontech/erigon-lib/common" rlp2 "github.com/erigontech/erigon-lib/rlp" types2 "github.com/erigontech/erigon-lib/types" - "github.com/erigontech/erigon/common/u256" "github.com/erigontech/erigon/rlp" ) @@ -79,15 +78,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 @@ -117,7 +107,7 @@ func (tx *SetCodeTransaction) AsMessage(s Signer, baseFee *big.Int, rules *chain 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 a5be3bef561..2e78009c6d8 100644 --- a/core/types/transaction.go +++ b/core/types/transaction.go @@ -74,7 +74,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 @@ -104,8 +103,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 d95cca228e1..de1ad3d85e4 100644 --- a/core/types/transaction_marshalling.go +++ b/core/types/transaction_marshalling.go @@ -494,12 +494,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() @@ -611,7 +608,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 60d4ecac042..4507048c4c5 100644 --- a/core/types/transaction_test.go +++ b/core/types/transaction_test.go @@ -692,10 +692,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),