Skip to content

Commit 8245c99

Browse files
authored
Effective gas price (#4759)
2 parents 7a89fb2 + 10be052 commit 8245c99

File tree

8 files changed

+104
-4
lines changed

8 files changed

+104
-4
lines changed

core/state_processor.go

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -334,6 +334,7 @@ func ApplyTransaction(bc ChainContext, author *common.Address, gp *GasPool, stat
334334
receipt := types.NewReceipt(root, failedExe, *usedGas)
335335
receipt.TxHash = tx.Hash()
336336
receipt.GasUsed = result.UsedGas
337+
receipt.EffectiveGasPrice = tx.EffectiveGasPrice(big.NewInt(0), nil)
337338
// if the transaction created a contract, store the creation address in the receipt.
338339
if msg.To() == nil {
339340
receipt.ContractAddress = crypto.CreateAddress(vmenv.Context.Origin, tx.Nonce())
@@ -415,6 +416,7 @@ func ApplyStakingTransaction(
415416
receipt = types.NewReceipt(root, false, *usedGas)
416417
receipt.TxHash = tx.Hash()
417418
receipt.GasUsed = gas
419+
receipt.EffectiveGasPrice = tx.EffectiveGasPrice(big.NewInt(0), nil)
418420

419421
if config.IsReceiptLog(header.Epoch()) {
420422
receipt.Logs = statedb.GetLogs(tx.Hash(), header.Number().Uint64(), header.Hash())

core/types/receipt.go

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ import (
2020
"bytes"
2121
"fmt"
2222
"io"
23+
"math/big"
2324
"unsafe"
2425

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

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

6264
type receiptMarshaling struct {
@@ -82,6 +84,7 @@ type receiptStorageRLP struct {
8284
ContractAddress common.Address
8385
Logs []*LogForStorage
8486
GasUsed uint64
87+
EffectiveGasPrice *big.Int `rlp:"optional"`
8588
}
8689

8790
// NewReceipt creates a barebone transaction receipt, copying the init fields.
@@ -166,6 +169,7 @@ func (r *ReceiptForStorage) EncodeRLP(w io.Writer) error {
166169
ContractAddress: r.ContractAddress,
167170
Logs: make([]*LogForStorage, len(r.Logs)),
168171
GasUsed: r.GasUsed,
172+
EffectiveGasPrice: r.EffectiveGasPrice,
169173
}
170174
for i, log := range r.Logs {
171175
enc.Logs[i] = (*LogForStorage)(log)
@@ -191,6 +195,7 @@ func (r *ReceiptForStorage) DecodeRLP(s *rlp.Stream) error {
191195
}
192196
// Assign the implementation fields
193197
r.TxHash, r.ContractAddress, r.GasUsed = dec.TxHash, dec.ContractAddress, dec.GasUsed
198+
r.EffectiveGasPrice = dec.EffectiveGasPrice
194199
return nil
195200
}
196201

core/types/receipt_test.go

Lines changed: 67 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,15 @@
11
package types
22

33
import (
4+
"math/big"
45
"reflect"
56
"testing"
67

78
ethcommon "github.com/ethereum/go-ethereum/common"
8-
99
"github.com/ethereum/go-ethereum/crypto"
10+
"github.com/ethereum/go-ethereum/rlp"
1011
"github.com/harmony-one/harmony/staking"
12+
"github.com/stretchr/testify/require"
1113
)
1214

1315
func TestFindLogsWithTopic(t *testing.T) {
@@ -112,3 +114,67 @@ func TestFindLogsWithTopic(t *testing.T) {
112114
}
113115
}
114116
}
117+
118+
// Test we can still parse receipt without EffectiveGasPrice for backwards compatibility, even
119+
// though it is required per the spec.
120+
func TestEffectiveGasPriceNotRequired(t *testing.T) {
121+
r := &Receipt{
122+
Status: ReceiptStatusFailed,
123+
CumulativeGasUsed: 1,
124+
Logs: []*Log{},
125+
// derived fields:
126+
TxHash: ethcommon.BytesToHash([]byte{0x03, 0x14}),
127+
ContractAddress: ethcommon.HexToAddress("0x5a443704dd4b594b382c22a083e2bd3090a6fef3"),
128+
GasUsed: 1,
129+
}
130+
131+
r.EffectiveGasPrice = nil
132+
b, err := r.MarshalJSON()
133+
if err != nil {
134+
t.Fatal("error marshaling receipt to json:", err)
135+
}
136+
r2 := Receipt{}
137+
err = r2.UnmarshalJSON(b)
138+
if err != nil {
139+
t.Fatal("error unmarshalling receipt from json:", err)
140+
}
141+
}
142+
143+
func TestReceiptEncDec(t *testing.T) {
144+
r := ReceiptForStorage(Receipt{
145+
Status: ReceiptStatusFailed,
146+
CumulativeGasUsed: 1,
147+
Logs: []*Log{},
148+
// derived fields:
149+
TxHash: ethcommon.BytesToHash([]byte{0x03, 0x14}),
150+
ContractAddress: ethcommon.HexToAddress("0x5a443704dd4b594b382c22a083e2bd3090a6fef3"),
151+
GasUsed: 1,
152+
EffectiveGasPrice: big.NewInt(1),
153+
})
154+
155+
bytes, err := rlp.EncodeToBytes(&r)
156+
if err != nil {
157+
t.Fatal("error encoding receipt to bytes:", err)
158+
}
159+
160+
r2 := ReceiptForStorage{}
161+
err = rlp.DecodeBytes(bytes, &r2)
162+
if err != nil {
163+
t.Fatal("error decoding receipt from bytes:", err)
164+
}
165+
166+
require.Equal(t, r, r2)
167+
}
168+
169+
func TestReceiptDecodeEmptyEffectiveGasPrice(t *testing.T) {
170+
r := ReceiptForStorage(Receipt{})
171+
172+
bytes, err := rlp.EncodeToBytes(&r)
173+
require.NoError(t, err, "error encoding receipt to bytes")
174+
175+
r2 := ReceiptForStorage{}
176+
err = rlp.DecodeBytes(bytes, &r2)
177+
require.NoError(t, err, "error decoding receipt from bytes")
178+
179+
require.EqualValues(t, r.EffectiveGasPrice, r2.EffectiveGasPrice)
180+
}

core/types/transaction.go

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -178,6 +178,10 @@ func (d *txdata) CopyFrom(d2 *txdata) {
178178
d.Hash = copyHash(d2.Hash)
179179
}
180180

181+
func (d *txdata) effectiveGasPrice(dst *big.Int, baseFee *big.Int) *big.Int {
182+
return dst.Set(d.Price)
183+
}
184+
181185
type txdataMarshaling struct {
182186
AccountNonce hexutil.Uint64
183187
Price *hexutil.Big
@@ -532,6 +536,11 @@ func (tx *Transaction) SenderAddress() (common.Address, error) {
532536
return addr, nil
533537
}
534538

539+
// EffectiveGasPrice returns the effective gas price of the transaction.
540+
func (tx *Transaction) EffectiveGasPrice(dst *big.Int, baseFee *big.Int) *big.Int {
541+
return tx.data.effectiveGasPrice(dst, baseFee)
542+
}
543+
535544
// TxByNonce implements the sort interface to allow sorting a list of transactions
536545
// by their nonces. This is usually only useful for sorting transactions from a
537546
// single account, otherwise a nonce comparison doesn't make much sense.

rpc/harmony/eth/types.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -152,6 +152,7 @@ func NewReceipt(senderAddr common.Address, tx *types.EthTransaction, blockHash c
152152
"contractAddress": nil,
153153
"logs": receipt.Logs,
154154
"logsBloom": receipt.Bloom,
155+
"effectiveGasPrice": hexutil.Big(*receipt.EffectiveGasPrice),
155156
}
156157

157158
// Assign receipt status or post state.

rpc/harmony/v1/types.go

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -188,6 +188,7 @@ type TxReceipt struct {
188188
To string `json:"to"`
189189
Root hexutil.Bytes `json:"root"`
190190
Status hexutil.Uint `json:"status"`
191+
EffectiveGasPrice hexutil.Big `json:"effectiveGasPrice"`
191192
}
192193

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

210212
// CxReceipt represents a CxReceipt that will serialize to the RPC representation of a CxReceipt
@@ -359,6 +361,7 @@ func NewTxReceipt(
359361
To: receiver,
360362
Root: receipt.PostState,
361363
Status: hexutil.Uint(receipt.Status),
364+
EffectiveGasPrice: hexutil.Big(*receipt.EffectiveGasPrice),
362365
}
363366

364367
// Set empty array for empty logs
@@ -401,6 +404,7 @@ func NewStakingTxReceipt(
401404
Type: hexutil.Uint64(tx.StakingType()),
402405
Root: receipt.PostState,
403406
Status: hexutil.Uint(receipt.Status),
407+
EffectiveGasPrice: hexutil.Big(*receipt.EffectiveGasPrice),
404408
}
405409

406410
// Set empty array for empty logs

rpc/harmony/v2/types.go

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -218,6 +218,7 @@ type TxReceipt struct {
218218
To string `json:"to"`
219219
Root hexutil.Bytes `json:"root"`
220220
Status uint `json:"status"`
221+
EffectiveGasPrice uint64 `json:"effectiveGasPrice"`
221222
}
222223

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

240242
// CxReceipt represents a CxReceipt that will serialize to the RPC representation of a CxReceipt
@@ -388,6 +390,7 @@ func NewTxReceipt(
388390
To: receiver,
389391
Root: receipt.PostState,
390392
Status: uint(receipt.Status),
393+
EffectiveGasPrice: (*receipt.EffectiveGasPrice).Uint64(),
391394
}
392395

393396
// Set optionals
@@ -437,6 +440,7 @@ func NewStakingTxReceipt(
437440
Type: tx.StakingType(),
438441
Root: receipt.PostState,
439442
Status: uint(receipt.Status),
443+
EffectiveGasPrice: (*receipt.EffectiveGasPrice).Uint64(),
440444
}
441445

442446
// Set empty array for empty logs

staking/types/transaction.go

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,10 @@ func (d *txdata) CopyFrom(d2 *txdata) {
5757
d.Hash = copyHash(d2.Hash)
5858
}
5959

60+
func (d *txdata) effectiveGasPrice(dst *big.Int, baseFee *big.Int) *big.Int {
61+
return dst.Set(d.Price)
62+
}
63+
6064
func copyHash(hash *common.Hash) *common.Hash {
6165
if hash == nil {
6266
return nil
@@ -263,6 +267,11 @@ func (tx *StakingTransaction) IsEthCompatible() bool {
263267
return false
264268
}
265269

270+
// EffectiveGasPrice returns the effective gas price of the transaction.
271+
func (tx *StakingTransaction) EffectiveGasPrice(dst *big.Int, baseFee *big.Int) *big.Int {
272+
return tx.data.effectiveGasPrice(dst, baseFee)
273+
}
274+
266275
type writeCounter common.StorageSize
267276

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

0 commit comments

Comments
 (0)