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

Add CIP-66 receipt field feeInFeeCurrency #2292

Draft
wants to merge 11 commits into
base: master
Choose a base branch
from
1 change: 1 addition & 0 deletions core/rawdb/accessors_chain.go
Original file line number Diff line number Diff line change
Expand Up @@ -670,6 +670,7 @@ type storedReceiptRLP struct {
PostStateOrStatus []byte
CumulativeGasUsed uint64
Logs []*types.LogForStorage
FeeInFeeCurrency *big.Int
}

// ReceiptLogs is a barebone version of ReceiptForStorage which only keeps
Expand Down
1 change: 1 addition & 0 deletions core/state_processor.go
Original file line number Diff line number Diff line change
Expand Up @@ -172,6 +172,7 @@ func applyTransaction(msg types.Message, config *params.ChainConfig, gp *GasPool
} else {
receipt.Status = types.ReceiptStatusSuccessful
}
receipt.FeeInFeeCurrency = result.FeeInFeeCurrency
receipt.TxHash = tx.Hash()
receipt.GasUsed = result.UsedGas

Expand Down
47 changes: 26 additions & 21 deletions core/state_transition.go
Original file line number Diff line number Diff line change
Expand Up @@ -60,21 +60,22 @@ import (
// 5. Run Script section
// 6. Derive new state root
type StateTransition struct {
gp *GasPool
msg Message
gas uint64
gasPrice *big.Int
gasFeeCap *big.Int
gasTipCap *big.Int
initialGas uint64
value *big.Int
data []byte
state vm.StateDB
evm *vm.EVM
vmRunner vm.EVMRunner
gasPriceMinimum *big.Int
sysCtx *SysContractCallCtx
erc20FeeDebited *big.Int
gp *GasPool
msg Message
gas uint64
gasPrice *big.Int
gasFeeCap *big.Int
gasTipCap *big.Int
initialGas uint64
value *big.Int
data []byte
state vm.StateDB
evm *vm.EVM
vmRunner vm.EVMRunner
gasPriceMinimum *big.Int
sysCtx *SysContractCallCtx
erc20FeeDebited *big.Int // Total debited in erc20 gas currencies
feeInFeeCurrency *big.Int // total fee paid (debited - credited) in fee currency for CELO deno txs
}

// Message represents a message sent to a contract.
Expand Down Expand Up @@ -118,9 +119,10 @@ func CheckEthCompatibility(msg Message) error {
// ExecutionResult includes all output after executing given evm
// message no matter the execution itself is successful or not.
type ExecutionResult struct {
UsedGas uint64 // Total used gas but include the refunded gas
Err error // Any error encountered during the execution(listed in core/vm/errors.go)
ReturnData []byte // Returned data from evm(function result or data supplied with revert opcode)
UsedGas uint64 // Total used gas but include the refunded gas
Err error // Any error encountered during the execution(listed in core/vm/errors.go)
ReturnData []byte // Returned data from evm(function result or data supplied with revert opcode)
FeeInFeeCurrency *big.Int // Fee paid (debit - credit) on CELO denominated txs
}

// Unwrap returns the internal evm error which allows us for further
Expand Down Expand Up @@ -558,9 +560,10 @@ func (st *StateTransition) TransitionDb() (*ExecutionResult, error) {
return nil, err
}
return &ExecutionResult{
UsedGas: st.gasUsed(),
Err: vmerr,
ReturnData: ret,
UsedGas: st.gasUsed(),
Err: vmerr,
ReturnData: ret,
FeeInFeeCurrency: st.feeInFeeCurrency,
}, nil
}

Expand Down Expand Up @@ -602,6 +605,8 @@ func (st *StateTransition) creditTxFees(feeCurrencyRate *currency.ExchangeRate)
refund.Sub(st.erc20FeeDebited, totalTxFee) // refund = debited - tip - basefee
// No need to exchange gateway fee since it's it's deprecated on G fork,
// and MaxFeeInFeeCurrency can only be present in H fork (which implies G fork)
// Set receipt field
st.feeInFeeCurrency = totalTxFee
}

feeCurrency := st.msg.FeeCurrency()
Expand Down
9 changes: 3 additions & 6 deletions core/types/celo_denominated_tx.go
Original file line number Diff line number Diff line change
@@ -1,16 +1,11 @@
package types

import (
"errors"
"math/big"

"github.com/celo-org/celo-blockchain/common"
)

var (
ErrNonCeloDenominated error = errors.New("Tx not CeloDenominated")
)

type CeloDenominatedTx struct {
ChainID *big.Int
Nonce uint64
Expand Down Expand Up @@ -48,6 +43,9 @@ func (tx *CeloDenominatedTx) copy() TxData {
R: new(big.Int),
S: new(big.Int),
}
if tx.MaxFeeInFeeCurrency != nil {
cpy.MaxFeeInFeeCurrency = new(big.Int).Set(tx.MaxFeeInFeeCurrency)
}
copy(cpy.AccessList, tx.AccessList)
if tx.Value != nil {
cpy.Value.Set(tx.Value)
Expand Down Expand Up @@ -76,7 +74,6 @@ func (tx *CeloDenominatedTx) copy() TxData {
// accessors for innerTx.
func (tx *CeloDenominatedTx) txType() byte { return CeloDenominatedTxType }
func (tx *CeloDenominatedTx) chainID() *big.Int { return tx.ChainID }
func (tx *CeloDenominatedTx) protected() bool { return true }
func (tx *CeloDenominatedTx) accessList() AccessList { return tx.AccessList }
func (tx *CeloDenominatedTx) data() []byte { return tx.Data }
func (tx *CeloDenominatedTx) gas() uint64 { return tx.Gas }
Expand Down
3 changes: 0 additions & 3 deletions core/types/gen_header_json.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

6 changes: 6 additions & 0 deletions core/types/gen_receipt_json.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

72 changes: 68 additions & 4 deletions core/types/receipt.go
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,9 @@ type Receipt struct {
BlockHash common.Hash `json:"blockHash,omitempty"`
BlockNumber *big.Int `json:"blockNumber,omitempty"`
TransactionIndex uint `json:"transactionIndex"`

FeeInFeeCurrency *big.Int `json:"feeInFeeCurrency,omitempty"` // CIP-66 receipt field

}

type receiptMarshaling struct {
Expand All @@ -80,6 +83,7 @@ type receiptMarshaling struct {
GasUsed hexutil.Uint64
BlockNumber *hexutil.Big
TransactionIndex hexutil.Uint
FeeInFeeCurrency *hexutil.Big
}

// receiptRLP is the consensus encoding of a receipt.
Expand All @@ -90,11 +94,27 @@ type receiptRLP struct {
Logs []*Log
}

type celoDenominatedReceiptRLP struct {
PostStateOrStatus []byte
CumulativeGasUsed uint64
Bloom Bloom
Logs []*Log
FeeInFeeCurrency *big.Int
}

// storedReceiptRLP is the storage encoding of a receipt.
type storedReceiptRLP struct {
PostStateOrStatus []byte
CumulativeGasUsed uint64
Logs []*LogForStorage
FeeInFeeCurrency *big.Int
}

// storedPreCIP66ReceiptRLP is the storage encoding of a receipt before adding the FeeInFeeCurrency field
type storedPreCIP66ReceiptRLP struct {
PostStateOrStatus []byte
CumulativeGasUsed uint64
Logs []*LogForStorage
}

// v4StoredReceiptRLP is the storage encoding of a receipt used in database version 4.
Expand Down Expand Up @@ -145,7 +165,13 @@ func (r *Receipt) EncodeRLP(w io.Writer) error {
defer encodeBufferPool.Put(buf)
buf.Reset()
buf.WriteByte(r.Type)
if err := rlp.Encode(buf, data); err != nil {
var d interface{}
if r.Type == CeloDenominatedTxType {
d = &celoDenominatedReceiptRLP{r.statusEncoding(), r.CumulativeGasUsed, r.Bloom, r.Logs, r.FeeInFeeCurrency}
} else {
d = data
}
if err := rlp.Encode(buf, d); err != nil {
return err
}
return rlp.Encode(w, buf.Bytes())
Expand Down Expand Up @@ -176,12 +202,18 @@ func (r *Receipt) DecodeRLP(s *rlp.Stream) error {
return errEmptyTypedReceipt
}
r.Type = b[0]
if r.Type == AccessListTxType || r.Type == DynamicFeeTxType || r.Type == CeloDynamicFeeTxType || r.Type == CeloDynamicFeeTxV2Type || r.Type == CeloDenominatedTxType {
if r.Type == AccessListTxType || r.Type == DynamicFeeTxType || r.Type == CeloDynamicFeeTxType || r.Type == CeloDynamicFeeTxV2Type {
var dec receiptRLP
if err := rlp.DecodeBytes(b[1:], &dec); err != nil {
return err
}
return r.setFromRLP(dec)
} else if r.Type == CeloDenominatedTxType {
var dec celoDenominatedReceiptRLP
if err := rlp.DecodeBytes(b[1:], &dec); err != nil {
return err
}
return r.setFromCeloDenominatedRLP(dec)
}
return ErrTxTypeNotSupported
default:
Expand All @@ -194,6 +226,11 @@ func (r *Receipt) setFromRLP(data receiptRLP) error {
return r.setStatus(data.PostStateOrStatus)
}

func (r *Receipt) setFromCeloDenominatedRLP(data celoDenominatedReceiptRLP) error {
r.CumulativeGasUsed, r.Bloom, r.Logs, r.FeeInFeeCurrency = data.CumulativeGasUsed, data.Bloom, data.Logs, data.FeeInFeeCurrency
return r.setStatus(data.PostStateOrStatus)
}

func (r *Receipt) setStatus(postStateOrStatus []byte) error {
switch {
case bytes.Equal(postStateOrStatus, receiptStatusSuccessfulRLP):
Expand Down Expand Up @@ -226,6 +263,9 @@ func (r *Receipt) Size() common.StorageSize {
for _, log := range r.Logs {
size += common.StorageSize(len(log.Topics)*common.HashLength + len(log.Data))
}
if r.FeeInFeeCurrency != nil {
size += common.StorageSize(r.FeeInFeeCurrency.BitLen() / 8)
}
return size
}

Expand All @@ -240,6 +280,7 @@ func (r *ReceiptForStorage) EncodeRLP(w io.Writer) error {
PostStateOrStatus: (*Receipt)(r).statusEncoding(),
CumulativeGasUsed: r.CumulativeGasUsed,
Logs: make([]*LogForStorage, len(r.Logs)),
FeeInFeeCurrency: r.FeeInFeeCurrency,
}
for i, log := range r.Logs {
enc.Logs[i] = (*LogForStorage)(log)
Expand All @@ -261,6 +302,9 @@ func (r *ReceiptForStorage) DecodeRLP(s *rlp.Stream) error {
if err := decodeStoredReceiptRLP(r, blob); err == nil {
return nil
}
if err := decodePreCIP66ReceiptRLP(r, blob); err == nil {
return nil
}
if err := decodeV3StoredReceiptRLP(r, blob); err == nil {
return nil
}
Expand All @@ -282,7 +326,27 @@ func decodeStoredReceiptRLP(r *ReceiptForStorage, blob []byte) error {
r.Logs[i] = (*Log)(log)
}
r.Bloom = CreateBloom(Receipts{(*Receipt)(r)})
// rlp encodes the nil value as a zero instance
if stored.FeeInFeeCurrency != nil && stored.FeeInFeeCurrency.Cmp(common.Big0) != 0 {
r.FeeInFeeCurrency = stored.FeeInFeeCurrency
}
return nil
}

func decodePreCIP66ReceiptRLP(r *ReceiptForStorage, blob []byte) error {
var stored storedPreCIP66ReceiptRLP
if err := rlp.DecodeBytes(blob, &stored); err != nil {
return err
}
if err := (*Receipt)(r).setStatus(stored.PostStateOrStatus); err != nil {
return err
}
r.CumulativeGasUsed = stored.CumulativeGasUsed
r.Logs = make([]*Log, len(stored.Logs))
for i, log := range stored.Logs {
r.Logs[i] = (*Log)(log)
}
r.Bloom = CreateBloom(Receipts{(*Receipt)(r)})
return nil
}

Expand Down Expand Up @@ -354,7 +418,8 @@ func (rs Receipts) EncodeIndex(i int, w *bytes.Buffer) {
rlp.Encode(w, data)
case CeloDenominatedTxType:
w.WriteByte(CeloDenominatedTxType)
rlp.Encode(w, data)
cip66data := &celoDenominatedReceiptRLP{r.statusEncoding(), r.CumulativeGasUsed, r.Bloom, r.Logs, r.FeeInFeeCurrency}
rlp.Encode(w, cip66data)
default:
// For unsupported types, write nothing. Since this is for
// DeriveSha, the error will be caught matching the derived hash
Expand All @@ -366,7 +431,6 @@ func (rs Receipts) EncodeIndex(i int, w *bytes.Buffer) {
// data and contextual infos like containing block and transactions.
func (r Receipts) DeriveFields(config *params.ChainConfig, hash common.Hash, number uint64, txs Transactions) error {
signer := MakeSigner(config, new(big.Int).SetUint64(number))

logIndex := uint(0)
if len(txs) != len(r) {
// The receipts may include an additional "block finalization" receipt (only IBFT)
Expand Down
8 changes: 7 additions & 1 deletion core/types/transaction.go
Original file line number Diff line number Diff line change
Expand Up @@ -487,7 +487,13 @@ func (tx *Transaction) GatewaySet() bool {
func (tx *Transaction) EthCompatible() bool { return tx.inner.ethCompatible() }

// MaxFeeInFeeCurrency returns the max fee in the fee_currency for celo denominated txs.
func (tx *Transaction) MaxFeeInFeeCurrency() *big.Int { return tx.inner.maxFeeInFeeCurrency() }
func (tx *Transaction) MaxFeeInFeeCurrency() *big.Int {
maxFee := tx.inner.maxFeeInFeeCurrency()
if maxFee == nil {
return nil
}
return new(big.Int).Set(maxFee)
}

// Fee calculates the fess paid by the transaction include the gateway fee.
func (tx *Transaction) Fee() *big.Int {
Expand Down
5 changes: 5 additions & 0 deletions core/types/transaction_signing.go
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,8 @@ type sigCache struct {
func MakeSigner(config *params.ChainConfig, blockNumber *big.Int) Signer {
var signer Signer
switch {
case config.IsHFork(blockNumber):
signer = NewHForkSigner(config.ChainID)
case config.IsGingerbreadP2(blockNumber):
signer = NewGingerbreadSigner(config.ChainID)
case config.IsEspresso(blockNumber):
Expand All @@ -63,6 +65,9 @@ func MakeSigner(config *params.ChainConfig, blockNumber *big.Int) Signer {
// have the current block number available, use MakeSigner instead.
func LatestSigner(config *params.ChainConfig) Signer {
if config.ChainID != nil {
if config.HForkBlock != nil {
return NewHForkSigner(config.ChainID)
}
if config.GingerbreadP2Block != nil {
return NewGingerbreadSigner(config.ChainID)
}
Expand Down
Loading
Loading