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

Effective gas price #4759

Merged
merged 13 commits into from
Jan 20, 2025
2 changes: 1 addition & 1 deletion .travis.yml
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ install:
# /home/travis/gopath/src/github.com/harmony-one/harmony
# https://docs.travis-ci.com/user/languages/go/#go-import-path
- echo $TRAVIS_PULL_REQUEST_BRANCH
- TEST_REPO_BRANCH="master"
- TEST_REPO_BRANCH="feature/effective-gas-price"
sophoah marked this conversation as resolved.
Show resolved Hide resolved
- git clone https://github.com/harmony-one/mcl.git $GOPATH/src/github.com/harmony-one/mcl
- git clone https://github.com/harmony-one/bls.git $GOPATH/src/github.com/harmony-one/bls
- git clone --branch $TEST_REPO_BRANCH https://github.com/harmony-one/harmony-test.git $GOPATH/src/github.com/harmony-one/harmony-test
Expand Down
2 changes: 2 additions & 0 deletions core/state_processor.go
Original file line number Diff line number Diff line change
Expand Up @@ -334,6 +334,7 @@ func ApplyTransaction(bc ChainContext, author *common.Address, gp *GasPool, stat
receipt := types.NewReceipt(root, failedExe, *usedGas)
receipt.TxHash = tx.Hash()
receipt.GasUsed = result.UsedGas
receipt.EffectiveGasPrice = tx.EffectiveGasPrice(big.NewInt(0), nil)
// if the transaction created a contract, store the creation address in the receipt.
if msg.To() == nil {
receipt.ContractAddress = crypto.CreateAddress(vmenv.Context.Origin, tx.Nonce())
Expand Down Expand Up @@ -415,6 +416,7 @@ func ApplyStakingTransaction(
receipt = types.NewReceipt(root, false, *usedGas)
receipt.TxHash = tx.Hash()
receipt.GasUsed = gas
receipt.EffectiveGasPrice = tx.EffectiveGasPrice(big.NewInt(0), nil)

if config.IsReceiptLog(header.Epoch()) {
receipt.Logs = statedb.GetLogs(tx.Hash(), header.Number().Uint64(), header.Hash())
Expand Down
11 changes: 8 additions & 3 deletions core/types/receipt.go
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ import (
"bytes"
"fmt"
"io"
"math/big"
"unsafe"

"github.com/ethereum/go-ethereum/common"
Expand Down Expand Up @@ -54,9 +55,10 @@ type Receipt struct {
Logs []*Log `json:"logs" gencodec:"required"`

// Implementation fields (don't reorder!)
TxHash common.Hash `json:"transactionHash" gencodec:"required"`
ContractAddress common.Address `json:"contractAddress"`
GasUsed uint64 `json:"gasUsed" gencodec:"required"`
TxHash common.Hash `json:"transactionHash" gencodec:"required"`
ContractAddress common.Address `json:"contractAddress"`
GasUsed uint64 `json:"gasUsed" gencodec:"required"`
EffectiveGasPrice *big.Int `json:"effectiveGasPrice"` // required, but tag omitted for backwards compatibility
}

type receiptMarshaling struct {
Expand All @@ -82,6 +84,7 @@ type receiptStorageRLP struct {
ContractAddress common.Address
Logs []*LogForStorage
GasUsed uint64
EffectiveGasPrice *big.Int `rlp:"optional"`
}

// NewReceipt creates a barebone transaction receipt, copying the init fields.
Expand Down Expand Up @@ -166,6 +169,7 @@ func (r *ReceiptForStorage) EncodeRLP(w io.Writer) error {
ContractAddress: r.ContractAddress,
Logs: make([]*LogForStorage, len(r.Logs)),
GasUsed: r.GasUsed,
EffectiveGasPrice: r.EffectiveGasPrice,
}
for i, log := range r.Logs {
enc.Logs[i] = (*LogForStorage)(log)
Expand All @@ -191,6 +195,7 @@ func (r *ReceiptForStorage) DecodeRLP(s *rlp.Stream) error {
}
// Assign the implementation fields
r.TxHash, r.ContractAddress, r.GasUsed = dec.TxHash, dec.ContractAddress, dec.GasUsed
r.EffectiveGasPrice = dec.EffectiveGasPrice
return nil
}

Expand Down
68 changes: 67 additions & 1 deletion core/types/receipt_test.go
Original file line number Diff line number Diff line change
@@ -1,13 +1,15 @@
package types

import (
"math/big"
"reflect"
"testing"

ethcommon "github.com/ethereum/go-ethereum/common"

"github.com/ethereum/go-ethereum/crypto"
"github.com/ethereum/go-ethereum/rlp"
"github.com/harmony-one/harmony/staking"
"github.com/stretchr/testify/require"
)

func TestFindLogsWithTopic(t *testing.T) {
Expand Down Expand Up @@ -112,3 +114,67 @@ func TestFindLogsWithTopic(t *testing.T) {
}
}
}

// Test we can still parse receipt without EffectiveGasPrice for backwards compatibility, even
// though it is required per the spec.
func TestEffectiveGasPriceNotRequired(t *testing.T) {
r := &Receipt{
Status: ReceiptStatusFailed,
CumulativeGasUsed: 1,
Logs: []*Log{},
// derived fields:
TxHash: ethcommon.BytesToHash([]byte{0x03, 0x14}),
ContractAddress: ethcommon.HexToAddress("0x5a443704dd4b594b382c22a083e2bd3090a6fef3"),
GasUsed: 1,
}

r.EffectiveGasPrice = nil
b, err := r.MarshalJSON()
if err != nil {
t.Fatal("error marshaling receipt to json:", err)
}
r2 := Receipt{}
err = r2.UnmarshalJSON(b)
if err != nil {
t.Fatal("error unmarshalling receipt from json:", err)
}
}

func TestReceiptEncDec(t *testing.T) {
r := ReceiptForStorage(Receipt{
Status: ReceiptStatusFailed,
CumulativeGasUsed: 1,
Logs: []*Log{},
// derived fields:
TxHash: ethcommon.BytesToHash([]byte{0x03, 0x14}),
ContractAddress: ethcommon.HexToAddress("0x5a443704dd4b594b382c22a083e2bd3090a6fef3"),
GasUsed: 1,
EffectiveGasPrice: big.NewInt(1),
})

bytes, err := rlp.EncodeToBytes(&r)
if err != nil {
t.Fatal("error encoding receipt to bytes:", err)
}

r2 := ReceiptForStorage{}
err = rlp.DecodeBytes(bytes, &r2)
if err != nil {
t.Fatal("error decoding receipt from bytes:", err)
}

require.Equal(t, r, r2)
}

func TestReceiptDecodeEmptyEffectiveGasPrice(t *testing.T) {
r := ReceiptForStorage(Receipt{})

bytes, err := rlp.EncodeToBytes(&r)
require.NoError(t, err, "error encoding receipt to bytes")

r2 := ReceiptForStorage{}
err = rlp.DecodeBytes(bytes, &r2)
require.NoError(t, err, "error decoding receipt from bytes")

require.EqualValues(t, r.EffectiveGasPrice, r2.EffectiveGasPrice)
}
9 changes: 9 additions & 0 deletions core/types/transaction.go
Original file line number Diff line number Diff line change
Expand Up @@ -178,6 +178,10 @@ func (d *txdata) CopyFrom(d2 *txdata) {
d.Hash = copyHash(d2.Hash)
}

func (d *txdata) effectiveGasPrice(dst *big.Int, baseFee *big.Int) *big.Int {
return dst.Set(d.Price)
}

type txdataMarshaling struct {
AccountNonce hexutil.Uint64
Price *hexutil.Big
Expand Down Expand Up @@ -532,6 +536,11 @@ func (tx *Transaction) SenderAddress() (common.Address, error) {
return addr, nil
}

// EffectiveGasPrice returns the effective gas price of the transaction.
func (tx *Transaction) EffectiveGasPrice(dst *big.Int, baseFee *big.Int) *big.Int {
return tx.data.effectiveGasPrice(dst, baseFee)
}

// TxByNonce implements the sort interface to allow sorting a list of transactions
// by their nonces. This is usually only useful for sorting transactions from a
// single account, otherwise a nonce comparison doesn't make much sense.
Expand Down
1 change: 1 addition & 0 deletions rpc/harmony/eth/types.go
Original file line number Diff line number Diff line change
Expand Up @@ -152,6 +152,7 @@ func NewReceipt(senderAddr common.Address, tx *types.EthTransaction, blockHash c
"contractAddress": nil,
"logs": receipt.Logs,
"logsBloom": receipt.Bloom,
"effectiveGasPrice": hexutil.Big(*receipt.EffectiveGasPrice),
}

// Assign receipt status or post state.
Expand Down
4 changes: 4 additions & 0 deletions rpc/harmony/v1/types.go
Original file line number Diff line number Diff line change
Expand Up @@ -188,6 +188,7 @@ type TxReceipt struct {
To string `json:"to"`
Root hexutil.Bytes `json:"root"`
Status hexutil.Uint `json:"status"`
EffectiveGasPrice hexutil.Big `json:"effectiveGasPrice"`
}

// StakingTxReceipt represents a staking transaction receipt that will serialize to the RPC representation.
Expand All @@ -205,6 +206,7 @@ type StakingTxReceipt struct {
Type hexutil.Uint64 `json:"type"`
Root hexutil.Bytes `json:"root"`
Status hexutil.Uint `json:"status"`
EffectiveGasPrice hexutil.Big `json:"effectiveGasPrice"`
}

// CxReceipt represents a CxReceipt that will serialize to the RPC representation of a CxReceipt
Expand Down Expand Up @@ -359,6 +361,7 @@ func NewTxReceipt(
To: receiver,
Root: receipt.PostState,
Status: hexutil.Uint(receipt.Status),
EffectiveGasPrice: hexutil.Big(*receipt.EffectiveGasPrice),
}

// Set empty array for empty logs
Expand Down Expand Up @@ -401,6 +404,7 @@ func NewStakingTxReceipt(
Type: hexutil.Uint64(tx.StakingType()),
Root: receipt.PostState,
Status: hexutil.Uint(receipt.Status),
EffectiveGasPrice: hexutil.Big(*receipt.EffectiveGasPrice),
}

// Set empty array for empty logs
Expand Down
4 changes: 4 additions & 0 deletions rpc/harmony/v2/types.go
Original file line number Diff line number Diff line change
Expand Up @@ -218,6 +218,7 @@ type TxReceipt struct {
To string `json:"to"`
Root hexutil.Bytes `json:"root"`
Status uint `json:"status"`
EffectiveGasPrice uint64 `json:"effectiveGasPrice"`
}

// StakingTxReceipt represents a staking transaction receipt that will serialize to the RPC representation.
Expand All @@ -235,6 +236,7 @@ type StakingTxReceipt struct {
Type staking.Directive `json:"type"`
Root hexutil.Bytes `json:"root"`
Status uint `json:"status"`
EffectiveGasPrice uint64 `json:"effectiveGasPrice"`
}

// CxReceipt represents a CxReceipt that will serialize to the RPC representation of a CxReceipt
Expand Down Expand Up @@ -388,6 +390,7 @@ func NewTxReceipt(
To: receiver,
Root: receipt.PostState,
Status: uint(receipt.Status),
EffectiveGasPrice: (*receipt.EffectiveGasPrice).Uint64(),
}

// Set optionals
Expand Down Expand Up @@ -437,6 +440,7 @@ func NewStakingTxReceipt(
Type: tx.StakingType(),
Root: receipt.PostState,
Status: uint(receipt.Status),
EffectiveGasPrice: (*receipt.EffectiveGasPrice).Uint64(),
}

// Set empty array for empty logs
Expand Down
9 changes: 9 additions & 0 deletions staking/types/transaction.go
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,10 @@ func (d *txdata) CopyFrom(d2 *txdata) {
d.Hash = copyHash(d2.Hash)
}

func (d *txdata) effectiveGasPrice(dst *big.Int, baseFee *big.Int) *big.Int {
return dst.Set(d.Price)
}

func copyHash(hash *common.Hash) *common.Hash {
if hash == nil {
return nil
Expand Down Expand Up @@ -263,6 +267,11 @@ func (tx *StakingTransaction) IsEthCompatible() bool {
return false
}

// EffectiveGasPrice returns the effective gas price of the transaction.
func (tx *StakingTransaction) EffectiveGasPrice(dst *big.Int, baseFee *big.Int) *big.Int {
return tx.data.effectiveGasPrice(dst, baseFee)
}

type writeCounter common.StorageSize

func (c *writeCounter) Write(b []byte) (int, error) {
Expand Down