Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Handle migrated celo transactions #150

Merged
merged 15 commits into from
Jun 21, 2024
Merged
2 changes: 1 addition & 1 deletion accounts/external/backend.go
Original file line number Diff line number Diff line change
Expand Up @@ -215,7 +215,7 @@ func (api *ExternalSigner) SignTx(account accounts.Account, tx *types.Transactio
switch tx.Type() {
case types.LegacyTxType, types.AccessListTxType:
args.GasPrice = (*hexutil.Big)(tx.GasPrice())
case types.DynamicFeeTxType, types.CeloDynamicFeeTxType, types.CeloDenominatedTxType:
case types.DynamicFeeTxType, types.CeloDynamicFeeTxV2Type, types.CeloDenominatedTxType:
args.MaxFeePerGas = (*hexutil.Big)(tx.GasFeeCap())
args.MaxPriorityFeePerGas = (*hexutil.Big)(tx.GasTipCap())
default:
Expand Down
2 changes: 1 addition & 1 deletion core/blockchain_celo_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -77,7 +77,7 @@ func testNativeTransferWithFeeCurrency(t *testing.T, scheme string, feeCurrencyA
_, blocks, _ := GenerateChainWithGenesis(gspec, engine, 1, func(i int, b *BlockGen) {
b.SetCoinbase(common.Address{1})

txdata := &types.CeloDynamicFeeTx{
txdata := &types.CeloDynamicFeeTxV2{
ChainID: gspec.Config.ChainID,
Nonce: 0,
To: &aa,
Expand Down
2 changes: 1 addition & 1 deletion core/state_processor.go
Original file line number Diff line number Diff line change
Expand Up @@ -153,7 +153,7 @@ func applyTransaction(msg *Message, config *params.ChainConfig, gp *GasPool, sta
*receipt.DepositReceiptVersion = types.CanyonDepositReceiptVersion
}
}
if tx.Type() == types.CeloDynamicFeeTxType {
if tx.Type() == types.CeloDynamicFeeTxV2Type {
alternativeBaseFee := evm.Context.BaseFee
if msg.FeeCurrency != nil {
alternativeBaseFee, err = exchange.ConvertGoldToCurrency(evm.Context.ExchangeRates, msg.FeeCurrency, evm.Context.BaseFee)
Expand Down
2 changes: 1 addition & 1 deletion core/state_transition.go
Original file line number Diff line number Diff line change
Expand Up @@ -212,7 +212,7 @@ func TransactionToMessage(tx *types.Transaction, s types.Signer, baseFee *big.In
}
// If baseFee provided, set gasPrice to effectiveGasPrice.
if baseFee != nil {
if tx.Type() == types.CeloDynamicFeeTxType {
if tx.Type() == types.CeloDynamicFeeTxV2Type {
var err error
baseFee, err = exchange.ConvertGoldToCurrency(exchangeRates, msg.FeeCurrency, baseFee)
if err != nil {
Expand Down
2 changes: 1 addition & 1 deletion core/txpool/legacypool/celo_list_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ import (
)

func txC(nonce int, feeCap int, tipCap int, gas int, currency *common.Address) *types.Transaction {
return types.NewTx(&types.CeloDynamicFeeTx{
return types.NewTx(&types.CeloDynamicFeeTxV2{
GasFeeCap: big.NewInt(int64(feeCap)),
GasTipCap: big.NewInt(int64(tipCap)),
FeeCurrency: currency,
Expand Down
4 changes: 2 additions & 2 deletions core/txpool/legacypool/legacypool.go
Original file line number Diff line number Diff line change
Expand Up @@ -290,7 +290,7 @@ func New(config Config, chain BlockChain) *LegacyPool {
// pool, specifically, whether it is a Legacy, AccessList or Dynamic transaction.
func (pool *LegacyPool) Filter(tx *types.Transaction) bool {
switch tx.Type() {
case types.LegacyTxType, types.AccessListTxType, types.DynamicFeeTxType, types.CeloDynamicFeeTxType:
case types.LegacyTxType, types.AccessListTxType, types.DynamicFeeTxType, types.CeloDynamicFeeTxV2Type:
return true
default:
return false
Expand Down Expand Up @@ -642,7 +642,7 @@ func (pool *LegacyPool) validateTxBasics(tx *types.Transaction, local bool) erro
types.LegacyTxType,
types.AccessListTxType,
types.DynamicFeeTxType,
types.CeloDynamicFeeTxType),
types.CeloDynamicFeeTxV2Type),
MaxSize: txMaxSize,
MinTip: pool.gasTip.Load().ToBig(),
EffectiveGasCeil: pool.config.EffectiveGasCeil,
Expand Down
6 changes: 2 additions & 4 deletions core/types/celo_denominated_tx.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,8 @@ import (
"github.com/ethereum/go-ethereum/rlp"
)

const CeloDenominatedTxType = 0x7a

type CeloDenominatedTx struct {
ChainID *big.Int
Nonce uint64
Expand Down Expand Up @@ -115,7 +117,3 @@ func (tx *CeloDenominatedTx) encode(b *bytes.Buffer) error {
func (tx *CeloDenominatedTx) decode(input []byte) error {
return rlp.DecodeBytes(input, tx)
}

func (tx *CeloDenominatedTx) feeCurrency() *common.Address { return tx.FeeCurrency }

func (tx *CeloDenominatedTx) maxFeeInFeeCurrency() *big.Int { return tx.MaxFeeInFeeCurrency }
60 changes: 39 additions & 21 deletions core/types/celo_dynamic_fee_tx.go
Original file line number Diff line number Diff line change
@@ -1,4 +1,18 @@
// TODO: needs copyright header?
// Copyright 2024 The Celo Authors
// This file is part of the celo library.
//
// The celo library is free software: you can redistribute it and/or modify
// it under the terms of the GNU Lesser General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// The celo library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public License
// along with the celo library. If not, see <http://www.gnu.org/licenses/>.

package types

Expand All @@ -10,19 +24,21 @@ import (
"github.com/ethereum/go-ethereum/rlp"
)

// CeloDynamicFeeTx represents a CIP-64 transaction.
type CeloDynamicFeeTx struct {
ChainID *big.Int
Nonce uint64
GasTipCap *big.Int
GasFeeCap *big.Int
Gas uint64
To *common.Address `rlp:"nil"` // nil means contract creation
Value *big.Int
Data []byte
AccessList AccessList
const CeloDynamicFeeTxType = 0x7c

FeeCurrency *common.Address `rlp:"nil"` // nil means native currency
type CeloDynamicFeeTx struct {
ChainID *big.Int
Nonce uint64
GasTipCap *big.Int
GasFeeCap *big.Int
Gas uint64
FeeCurrency *common.Address `rlp:"nil"` // nil means native currency
GatewayFeeRecipient *common.Address `rlp:"nil"` // nil means no gateway fee is paid
GatewayFee *big.Int `rlp:"nil"`
To *common.Address `rlp:"nil"` // nil means contract creation
Value *big.Int
Data []byte
AccessList AccessList

// Signature values
V *big.Int `json:"v" gencodec:"required"`
Expand All @@ -33,13 +49,15 @@ type CeloDynamicFeeTx struct {
// copy creates a deep copy of the transaction data and initializes all fields.
func (tx *CeloDynamicFeeTx) copy() TxData {
cpy := &CeloDynamicFeeTx{
Nonce: tx.Nonce,
To: copyAddressPtr(tx.To),
Data: common.CopyBytes(tx.Data),
Gas: tx.Gas,
FeeCurrency: copyAddressPtr(tx.FeeCurrency),
Nonce: tx.Nonce,
To: copyAddressPtr(tx.To),
Data: common.CopyBytes(tx.Data),
Gas: tx.Gas,
FeeCurrency: copyAddressPtr(tx.FeeCurrency),
GatewayFeeRecipient: copyAddressPtr(tx.GatewayFeeRecipient),
// These are copied below.
AccessList: make(AccessList, len(tx.AccessList)),
GatewayFee: new(big.Int),
Value: new(big.Int),
ChainID: new(big.Int),
GasTipCap: new(big.Int),
Expand All @@ -61,6 +79,9 @@ func (tx *CeloDynamicFeeTx) copy() TxData {
if tx.GasFeeCap != nil {
cpy.GasFeeCap.Set(tx.GasFeeCap)
}
if tx.GatewayFee != nil {
cpy.GatewayFee.Set(tx.GatewayFee)
}
if tx.V != nil {
cpy.V.Set(tx.V)
}
Expand Down Expand Up @@ -113,6 +134,3 @@ func (tx *CeloDynamicFeeTx) encode(b *bytes.Buffer) error {
func (tx *CeloDynamicFeeTx) decode(input []byte) error {
return rlp.DecodeBytes(input, tx)
}

func (tx *CeloDynamicFeeTx) feeCurrency() *common.Address { return tx.FeeCurrency }
func (tx *CeloDynamicFeeTx) maxFeeInFeeCurrency() *big.Int { return nil }
131 changes: 131 additions & 0 deletions core/types/celo_dynamic_fee_tx_v2.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,131 @@
// Copyright 2024 The Celo Authors
// This file is part of the celo library.
//
// The celo library is free software: you can redistribute it and/or modify
// it under the terms of the GNU Lesser General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// The celo library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public License
// along with the celo library. If not, see <http://www.gnu.org/licenses/>.

package types

import (
"bytes"
"math/big"

"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/rlp"
)

const CeloDynamicFeeTxV2Type = 0x7b

// CeloDynamicFeeTxV2 represents a CIP-64 transaction.
type CeloDynamicFeeTxV2 struct {
ChainID *big.Int
Nonce uint64
GasTipCap *big.Int
GasFeeCap *big.Int
Gas uint64
To *common.Address `rlp:"nil"` // nil means contract creation
Value *big.Int
Data []byte
AccessList AccessList

FeeCurrency *common.Address `rlp:"nil"` // nil means native currency

// Signature values
V *big.Int `json:"v" gencodec:"required"`
R *big.Int `json:"r" gencodec:"required"`
S *big.Int `json:"s" gencodec:"required"`
}

// copy creates a deep copy of the transaction data and initializes all fields.
func (tx *CeloDynamicFeeTxV2) copy() TxData {
cpy := &CeloDynamicFeeTxV2{
Nonce: tx.Nonce,
To: copyAddressPtr(tx.To),
Data: common.CopyBytes(tx.Data),
Gas: tx.Gas,
FeeCurrency: copyAddressPtr(tx.FeeCurrency),
// These are copied below.
AccessList: make(AccessList, len(tx.AccessList)),
Value: new(big.Int),
ChainID: new(big.Int),
GasTipCap: new(big.Int),
GasFeeCap: new(big.Int),
V: new(big.Int),
R: new(big.Int),
S: new(big.Int),
}
copy(cpy.AccessList, tx.AccessList)
if tx.Value != nil {
cpy.Value.Set(tx.Value)
}
if tx.ChainID != nil {
cpy.ChainID.Set(tx.ChainID)
}
if tx.GasTipCap != nil {
cpy.GasTipCap.Set(tx.GasTipCap)
}
if tx.GasFeeCap != nil {
cpy.GasFeeCap.Set(tx.GasFeeCap)
}
if tx.V != nil {
cpy.V.Set(tx.V)
}
if tx.R != nil {
cpy.R.Set(tx.R)
}
if tx.S != nil {
cpy.S.Set(tx.S)
}
return cpy
}

// accessors for innerTx.
func (tx *CeloDynamicFeeTxV2) txType() byte { return CeloDynamicFeeTxV2Type }
func (tx *CeloDynamicFeeTxV2) chainID() *big.Int { return tx.ChainID }
func (tx *CeloDynamicFeeTxV2) accessList() AccessList { return tx.AccessList }
func (tx *CeloDynamicFeeTxV2) data() []byte { return tx.Data }
func (tx *CeloDynamicFeeTxV2) gas() uint64 { return tx.Gas }
func (tx *CeloDynamicFeeTxV2) gasFeeCap() *big.Int { return tx.GasFeeCap }
func (tx *CeloDynamicFeeTxV2) gasTipCap() *big.Int { return tx.GasTipCap }
func (tx *CeloDynamicFeeTxV2) gasPrice() *big.Int { return tx.GasFeeCap }
func (tx *CeloDynamicFeeTxV2) value() *big.Int { return tx.Value }
func (tx *CeloDynamicFeeTxV2) nonce() uint64 { return tx.Nonce }
func (tx *CeloDynamicFeeTxV2) to() *common.Address { return tx.To }
func (tx *CeloDynamicFeeTxV2) isSystemTx() bool { return false }

func (tx *CeloDynamicFeeTxV2) effectiveGasPrice(dst *big.Int, baseFee *big.Int) *big.Int {
if baseFee == nil {
return dst.Set(tx.GasFeeCap)
}
tip := dst.Sub(tx.GasFeeCap, baseFee)
if tip.Cmp(tx.GasTipCap) > 0 {
tip.Set(tx.GasTipCap)
}
return tip.Add(tip, baseFee)
}

func (tx *CeloDynamicFeeTxV2) rawSignatureValues() (v, r, s *big.Int) {
return tx.V, tx.R, tx.S
}

func (tx *CeloDynamicFeeTxV2) setSignatureValues(chainID, v, r, s *big.Int) {
tx.ChainID, tx.V, tx.R, tx.S = chainID, v, r, s
}

func (tx *CeloDynamicFeeTxV2) encode(b *bytes.Buffer) error {
return rlp.Encode(b, tx)
}

func (tx *CeloDynamicFeeTxV2) decode(input []byte) error {
return rlp.DecodeBytes(input, tx)
}
49 changes: 44 additions & 5 deletions core/types/celo_transaction.go
Original file line number Diff line number Diff line change
@@ -1,9 +1,48 @@
// Copyright 2024 The Celo Authors
// This file is part of the celo library.
//
// The celo library is free software: you can redistribute it and/or modify
// it under the terms of the GNU Lesser General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// The celo library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public License
// along with the celo library. If not, see <http://www.gnu.org/licenses/>.

package types

import (
"math/big"

"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/common/exchange"
)

// FeeCurrency returns the fee currency of the transaction if there is one.
func (tx *Transaction) FeeCurrency() *common.Address {
var feeCurrency *common.Address
switch t := tx.inner.(type) {
case *CeloDynamicFeeTxV2:
feeCurrency = t.FeeCurrency
}
return feeCurrency
}

// MaxFeeInFeeCurrency returns the maximum fee in the fee currency of the transaction if there is one.
func (tx *Transaction) MaxFeeInFeeCurrency() *big.Int {
piersy marked this conversation as resolved.
Show resolved Hide resolved
var maxFeeInFeeCurrency *big.Int
switch t := tx.inner.(type) {
case *CeloDenominatedTx:
maxFeeInFeeCurrency = t.MaxFeeInFeeCurrency
}
return maxFeeInFeeCurrency
}

// CompareWithRates compares the effective gas price of two transactions according to the exchange rates and
// the base fees in the transactions currencies.
func CompareWithRates(a, b *Transaction, ratesAndFees *exchange.RatesAndFees) int {
Expand All @@ -17,23 +56,23 @@ func CompareWithRates(a, b *Transaction, ratesAndFees *exchange.RatesAndFees) in
}
rates := ratesAndFees.Rates
if ratesAndFees.HasBaseFee() {
tipA := a.EffectiveGasTipValue(ratesAndFees.GetBaseFeeIn(a.inner.feeCurrency()))
tipB := b.EffectiveGasTipValue(ratesAndFees.GetBaseFeeIn(b.inner.feeCurrency()))
c, _ := exchange.CompareValue(rates, tipA, a.inner.feeCurrency(), tipB, b.inner.feeCurrency())
tipA := a.EffectiveGasTipValue(ratesAndFees.GetBaseFeeIn(a.FeeCurrency()))
tipB := b.EffectiveGasTipValue(ratesAndFees.GetBaseFeeIn(b.FeeCurrency()))
c, _ := exchange.CompareValue(rates, tipA, a.FeeCurrency(), tipB, b.FeeCurrency())
return c
}

// Compare fee caps if baseFee is not specified or effective tips are equal
feeA := a.inner.gasFeeCap()
feeB := b.inner.gasFeeCap()
c, _ := exchange.CompareValue(rates, feeA, a.inner.feeCurrency(), feeB, b.inner.feeCurrency())
c, _ := exchange.CompareValue(rates, feeA, a.FeeCurrency(), feeB, b.FeeCurrency())
if c != 0 {
return c
}

// Compare tips if effective tips and fee caps are equal
tipCapA := a.inner.gasTipCap()
tipCapB := b.inner.gasTipCap()
c, _ = exchange.CompareValue(rates, tipCapA, a.inner.feeCurrency(), tipCapB, b.inner.feeCurrency())
c, _ = exchange.CompareValue(rates, tipCapA, a.FeeCurrency(), tipCapB, b.FeeCurrency())
return c
}
Loading