8000 A list of APIs to be changed or added for dynamic gas price · Pull Request #1452 · klaytn/klaytn · GitHub
[go: up one dir, main page]
More Web Proxy on the site http://driver.im/
Skip to content
This repository was archived by the owner on Aug 19, 2024. It is now read-only.

A list of APIs to be changed or added for dynamic gas price #1452

Merged
21 commits merged into from Jun 30, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
137 changes: 90 additions & 47 deletions api/api_ethereum.go
8000

Large diffs are not rendered by default.

4 changes: 3 additions & 1 deletion api/api_ethereum_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -889,6 +889,7 @@ func TestEthereumAPI_GetTransactionByHash(t *testing.T) {

// Mock Backend functions.
mockBackend.EXPECT().ChainDB().Return(mockDBManager).Times(txs.Len())
mockBackend.EXPECT().BlockByHash(gomock.Any(), block.Hash()).Return(block, nil).Times(txs.Len())

// Get transaction by hash for each transaction types.
for i := 0; i < txs.Len(); i++ {
Expand Down Expand Up @@ -974,6 +975,7 @@ func TestEthereumAPI_GetTransactionReceipt(t *testing.T) {
).Times(txs.Len())
mockBackend.EXPECT().GetBlockReceipts(gomock.Any(), gomock.Any()).Return(receipts).Times(txs.Len())
mockBackend.EXPECT().ChainConfig().Return(dummyChainConfigForEthereumAPITest).Times(txs.Len())
mockBackend.EXPECT().HeaderByHash(gomock.Any(), block.Hash()).Return(block.Header(), nil).Times(txs.Len())

// Get receipt for each transaction types.
for i := 0; i < txs.Len(); i++ {
Expand All @@ -982,7 +984,7 @@ func TestEthereumAPI_GetTransactionReceipt(t *testing.T) {
t.Fatal(err)
}
txIdx := uint64(i)
checkEthTransactionReceiptFormat(t, block, receipts, receipt, RpcOutputReceipt(txs[i], block.Hash(), block.NumberU64(), txIdx, receiptMap[txs[i].Hash()]), txIdx)
checkEthTransactionReceiptFormat(t, block, receipts, receipt, RpcOutputReceipt(block.Header(), txs[i], block.Hash(), block.NumberU64(), txIdx, receiptMap[txs[i].Hash()]), txIdx)
}

mockCtrl.Finish()
Expand Down
9 changes: 4 additions & 5 deletions api/api_public_blockchain.go
Original file line number Diff line number Diff line change
Expand Up @@ -113,7 +113,7 @@ func (s *PublicBlockChainAPI) GetBlockReceipts(ctx context.Context, blockHash co
}
fieldsList := make([]map[string]interface{}, 0, len(receipts))
for index, receipt := range receipts {
fields := RpcOutputReceipt(txs[index], blockHash, block.NumberU64(), uint64(index), receipt)
fields := RpcOutputReceipt(block.Header(), txs[index], blockHash, block.NumberU64(), uint64(index), receipt)
fieldsList = append(fieldsList, fields)
}
return fieldsList, nil
Expand Down Expand Up @@ -532,11 +532,10 @@ func RpcOutputBlock(b *types.Block, td *big.Int, inclTx bool, fullTx bool, isEna
}

if isEnabledEthTxTypeFork {
if head.BaseFee != nil {
// KIP71 hardforked block
fields["baseFeePerGas"] = (*hexutil.Big)(head.BaseFee)
} else {
if head.BaseFee == nil {
fields["baseFeePerGas"] = (*hexutil.Big)(new(big.Int).SetUint64(params.ZeroBaseFee))
} else {
fields["baseFeePerGas"] = (*hexutil.Big)(head.BaseFee)
}
}

Expand Down
26 changes: 23 additions & 3 deletions api/api_public_transaction_pool.go
Original file line number Diff line number Diff line change
Expand Up @@ -202,10 +202,11 @@ func (s *PublicTransactionPoolAPI) GetRawTransactionByHash(ctx context.Context,

// RpcOutputReceipt converts a receipt to the RPC output with the associated information regarding to the
// block in which the receipt is included, the transaction that outputs the receipt, and the receipt itself.
func RpcOutputReceipt(tx *types.Transaction, blockHash common.Hash, blockNumber uint64, index uint64, receipt *types.Receipt) map[string]interface{} {
func RpcOutputReceipt(header *types.Header, tx *types.Transaction, blockHash common.Hash, blockNumber uint64, index uint64, receipt *types.Receipt) map[string]interface{} {
if tx == nil || receipt == nil {
return nil
}

fields := newRPCTransaction(tx, blockHash, blockNumber, index)

if receipt.Status != types.ReceiptStatusSuccessful {
Expand All @@ -218,6 +219,12 @@ func RpcOutputReceipt(tx *types.Transaction, blockHash common.Hash, blockNumber
fields["logsBloom"] = receipt.Bloom
fields["gasUsed"] = hexutil.Uint64(receipt.GasUsed)

if header != nil && header.BaseFee != nil {
fields["effectiveGasPrice"] = hexutil.Uint64(tx.EffectiveGasPrice(header.BaseFee).Uint64())
} else {
fields["effectiveGasPrice"] = hexutil.Uint64(tx.GasPrice().Uint64())
}

if receipt.Logs == nil {
fields["logs"] = [][]*types.Log{}
} else {
Expand Down Expand Up @@ -247,12 +254,25 @@ func (s *PublicTransactionPoolAPI) GetTransactionReceiptBySenderTxHash(ctx conte

// GetTransactionReceipt returns the transaction receipt for the given transaction hash.
func (s *PublicTransactionPoolAPI) GetTransactionReceipt(ctx context.Context, hash common.Hash) (map[string]interface{}, error) {
return RpcOutputReceipt(s.b.GetTxLookupInfoAndReceipt(ctx, hash)), nil
tx, blockHash, blockNumber, index, receipt := s.b.GetTxLookupInfoAndReceipt(ctx, hash)
return s.getTransactionReceipt(ctx, tx, blockHash, blockNumber, index, receipt)
}

// GetTransactionReceiptInCache returns the transaction receipt for the given transaction hash.
func (s *PublicTransactionPoolAPI) GetTransactionReceiptInCache(ctx context.Context, hash common.Hash) (map[string]interface{}, error) {
return RpcOutputReceipt(s.b.GetTxLookupInfoAndReceiptInCache(hash)), nil
tx, blockHash, blockNumber, index, receipt := s.b.GetTxLookupInfoAndReceiptInCache(hash)
return s.getTransactionReceipt(ctx, tx, blockHash, blockNumber, index, receipt)
}

// getTransactionReceipt returns the transaction receipt for the given transaction hash.
func (s *PublicTransactionPoolAPI) getTransactionReceipt(ctx context.Context, tx *types.Transaction, blockHash common.Hash,
blockNumber uint64, index uint64, receipt *types.Receipt,
) (map[string]interface{}, error) {
header, err := s.b.HeaderByHash(ctx, blockHash)
if err != nil {
return nil, err
}
return RpcOutputReceipt(header, tx, blockHash, blockNumber, index, receipt), nil
}

// sign is a helper function that signs a transaction with the private key of the given address.
Expand Down
1 change: 1 addition & 0 deletions api/tx_args.go
Original file line number Diff line number Diff line change
Expand Up @@ -159,6 +159,7 @@ func (args *SendTxArgs) setDefaults(ctx context.Context, b Backend) error {
}
args.Price = (*hexutil.Big)(price)
}
// TODO-Klaytn: need to delete this logic, klaytn namespace doesn't have EthereumDynamicFee type
if *args.TypeInt == types.TxTypeEthereumDynamicFee {
// TODO-Klaytn: The logic below is valid only when using a fixed gas price.
fixedGasPrice, err := b.SuggestPrice(ctx)
Expand Down
9 changes: 6 additions & 3 deletions blockchain/types/transaction.go
Original file line number Diff line number Diff line change
Expand Up @@ -32,12 +32,12 @@ import (
"sync/atomic"
"time"

"github.com/klaytn/klaytn/common/math"

"github.com/klaytn/klaytn/blockchain/types/accountkey"
"github.com/klaytn/klaytn/common"
"github.com/klaytn/klaytn/common/math"
"github.com/klaytn/klaytn/crypto"
"github.com/klaytn/klaytn/kerrors"
"github.com/klaytn/klaytn/params"
"github.com/klaytn/klaytn/rlp"
)

Expand Down Expand Up @@ -300,11 +300,14 @@ func (tx *Transaction) EffectiveGasTip(baseFee *big.Int) *big.Int {
// After hard fork, we need to consider new getEffectiveGasPrice API that operates differently
// effectiveGasPrice = msg.EffectiveGasPrice(baseFee)
func (tx *Transaction) EffectiveGasPrice(baseFee *big.Int) *big.Int {
if baseFee != nil {
return baseFee
}
if tx.Type() == TxTypeEthereumDynamicFee {
baseFee = new(big.Int).SetUint64(params.ZeroBaseFee)
te := tx.GetTxInternalData().(TxInternalDataBaseFee)
return math.BigMin(new(big.Int).Add(te.GetGasTipCap(), baseFee), te.GetGasFeeCap())
}

return tx.GasPrice()
}

Expand Down
29 changes: 22 additions & 7 deletions blockchain/types/transaction_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@ import (

"github.com/klaytn/klaytn/blockchain/types/accountkey"
"github.com/klaytn/klaytn/common"
"github.com/klaytn/klaytn/common/math"
"github.com/klaytn/klaytn/crypto"
"github.com/klaytn/klaytn/params"
"github.com/klaytn/klaytn/rlp"
Expand Down Expand Up @@ -328,25 +329,39 @@ func TestEIP1559TransactionEncode(t *testing.T) {
}

func TestEffectiveGasPrice(t *testing.T) {
legacyTx := NewTx(&TxInternalDataLegacy{Price: big.NewInt(1000)})
dynamicTx := NewTx(&TxInternalDataEthereumDynamicFee{GasFeeCap: big.NewInt(4000), GasTipCap: big.NewInt(1000)})
gasPrice := big.NewInt(1000)
gasFeeCap, gasTipCap := big.NewInt(4000), big.NewInt(1000)

legacyTx := NewTx(&TxInternalDataLegacy{Price: gasPrice})
dynamicTx := NewTx(&TxInternalDataEthereumDynamicFee{GasFeeCap: gasFeeCap, GasTipCap: gasTipCap})

var baseFee *big.Int

baseFee := big.NewInt(2000)
have := legacyTx.EffectiveGasPrice(baseFee)
want := big.NewInt(1000)
want := gasPrice
assert.Equal(t, want, have)

have = dynamicTx.EffectiveGasPrice(baseFee)
te := dynamicTx.GetTxInternalData().(TxInternalDataBaseFee)
want = math.BigMin(new(big.Int).Add(te.GetGasTipCap(), new(big.Int)), te.GetGasFeeCap())
assert.Equal(t, want, have)

baseFee = big.NewInt(2000)
have = legacyTx.EffectiveGasPrice(baseFee)
want = baseFee
assert.Equal(t, want, have)

have = dynamicTx.EffectiveGasPrice(baseFee)
want = big.NewInt(3000)
want = baseFee
assert.Equal(t, want, have)

baseFee = big.NewInt(0)
have = legacyTx.EffectiveGasPrice(baseFee)
want = big.NewInt(1000)
want = baseFee
assert.Equal(t, want, have)

have = dynamicTx.EffectiveGasPrice(baseFee)
want = big.NewInt(1000)
want = baseFee
assert.Equal(t, want, have)
}

Expand Down
2 changes: 1 addition & 1 deletion consensus/istanbul/backend/api.go
Original file line number Diff line number Diff line change
Expand Up @@ -361,7 +361,7 @@ func (api *APIExtension) makeRPCBlockOutput(b *types.Block,
numTxs := len(transactions)
rpcTransactions := make([]map[string]interface{}, numTxs)
for i, tx := range transactions {
rpcTransactions[i] = klaytnApi.RpcOutputReceipt(tx, hash, head.Number.Uint64(), uint64(i), receipts[i])
rpcTransactions[i] = klaytnApi.RpcOutputReceipt(head, tx, hash, head.Number.Uint64(), uint64(i), receipts[i])
}

r["committee"] = cInfo.committee
Expand Down
2 changes: 1 addition & 1 deletion datasync/chaindatafetcher/kafka/utils.go
Original file line number Diff line number Diff line change
Expand Up @@ -78,7 +78,7 @@ func makeBlockGroupOutput(blockchain *blockchain.BlockChain, block *types.Block,
numTxs := len(transactions)
rpcTransactions := make([]map[string]interface{}, numTxs)
for i, tx := range transactions {
rpcTransactions[i] = klaytnApi.RpcOutputReceipt(tx, hash, head.Number.Uint64(), uint64(i), receipts[i])
rpcTransactions[i] = klaytnApi.RpcOutputReceipt(head, tx, hash, head.Number.Uint64(), uint64(i), receipts[i])
}

r["committee"] = committee
Expand Down
4 changes: 2 additions & 2 deletions datasync/downloader/queue.go
Original file line number Diff line number Diff line change
Expand Up @@ -27,12 +27,12 @@ import (
"sync/atomic"
"time"

klaytnmetrics "github.com/klaytn/klaytn/metrics"

"github.com/klaytn/klaytn/blockchain/types"
"github.com/klaytn/klaytn/common"
"github.com/klaytn/klaytn/common/prque"
"github.com/rcrowley/go-metrics"

klaytnmetrics "github.com/klaytn/klaytn/metrics"
)

const (
Expand Down
34 changes: 24 additions & 10 deletions governance/api.go
Original file line number Diff line number Diff line change
Expand Up @@ -21,8 +21,9 @@ import (
"math/big"
"strings"

"github.com/klaytn/klaytn/common"
"github.com/klaytn/klaytn/common/hexutil"

"github.com/klaytn/klaytn/common"
"github.com/klaytn/klaytn/networks/rpc"
"github.com/klaytn/klaytn/params"
"github.com/klaytn/klaytn/reward"
Expand Down Expand Up @@ -62,22 +63,35 @@ var (
errInvalidUpperBound = errors.New("upperboundbasefee cannot be set lower than lowerboundbasefee")
)

// TODO-Klaytn-Governance: Refine this API and consider the gas price of txpool
// GasPriceAt returns the base fee of the given block in peb,
// or returns unit price by using governance if there is no base fee set in header,
// or returns gas price of txpool if the block is pending block.
func (api *GovernanceKlayAPI) GasPriceAt(num *rpc.BlockNumber) (*hexutil.Big, error) {
if num == nil || *num == rpc.LatestBlockNumber || *num == rpc.PendingBlockNumber {
ret := api.governance.UnitPrice()
return (*hexutil.Big)(big.NewInt(0).SetUint64(ret)), nil
if num == nil || *num == rpc.LatestBlockNumber {
header := api.chain.CurrentHeader()
if header.BaseFee == nil {
return (*hexutil.Big)(new(big.Int).SetUint64(api.governance.UnitPrice())), nil
}
return (*hexutil.Big)(header.BaseFee), nil
} else if *num == rpc.PendingBlockNumber {
txpool := api.governance.GetTxPool()
return (*hexutil.Big)(txpool.GasPrice()), nil
} else {
blockNum := num.Int64()
blockNum := num.Uint64()

if blockNum > api.chain.CurrentHeader().Number.Int64() {
// Return the BaseFee in header at the block number
header := api.chain.GetHeaderByNumber(blockNum)
if blockNum > api.chain.CurrentHeader().Number.Uint64() || header == nil {
return nil, errUnknownBlock
} else if header.BaseFee != nil {
return (*hexutil.Big)(header.BaseFee), nil
}

// Return the UnitPrice in governance data at the block number
if ret, err := api.GasPriceAtNumber(blockNum); err != nil {
return nil, err
} else {
return (*hexutil.Big)(big.NewInt(0).SetUint64(ret)), nil
return (*hexutil.Big)(new(big.Int).SetUint64(ret)), nil
}
}
}
Expand Down Expand Up @@ -245,8 +259,8 @@ func (api *PublicGovernanceAPI) isGovernanceModeBallot() bool {
return false
}

func (api *GovernanceKlayAPI) GasPriceAtNumber(num int64) (uint64, error) {
val, err := api.governance.GetGovernanceItemAtNumber(uint64(num), GovernanceKeyMapReverse[params.UnitPrice])
func (api *GovernanceKlayAPI) GasPriceAtNumber(num uint64) (uint64, error) {
val, err := api.governance.GetGovernanceItemAtNumber(num, GovernanceKeyMapReverse[params.UnitPrice])
if err != nil {
logger.Error("Failed to retrieve unit price", "err", err)
return 0, err
Expand Down
6 changes: 6 additions & 0 deletions governance/default.go
Original file line number Diff line number Diff line change
Expand Up @@ -168,11 +168,13 @@ type VoteMap struct {
// txPool is an interface for blockchain.TxPool used in governance package.
type txPool interface {
SetGasPrice(price *big.Int)
GasPrice() *big.Int
}

// blockChain is an interface for blockchain.Blockchain used in governance package.
type blockChain interface {
CurrentHeader() *types.Header
GetHeaderByNumber(val uint64) *types.Header
SetProposerPolicy(val uint64)
SetUseGiniCoeff(val bool)
SetLowerBoundBaseFee(val uint64)
Expand Down Expand Up @@ -1061,6 +1063,10 @@ func (gov *Governance) SetTxPool(txpool txPool) {
gov.TxPool = txpool
}

func (gov *Governance) GetTxPool() txPool {
return gov.TxPool
}

func GetGovernanceItemsFromChainConfig(config *params.ChainConfig) GovernanceSet {
g := NewGovernanceSet()

Expand Down
1 change: 1 addition & 0 deletions governance/interface.go
Original file line number Diff line number Diff line change
Expand Up @@ -97,6 +97,7 @@ type HeaderEngine interface {
SetMyVotingPower(t uint64)
SetBlockchain(chain blockChain)
SetTxPool(txpool txPool)
GetTxPool() txPool

// Get network params
GovernanceMode() string
Expand Down
4 changes: 4 additions & 0 deletions governance/mixed.go
Original file line number Diff line number Diff line change
Expand Up @@ -236,6 +236,10 @@ func (e *MixedEngine) SetTxPool(txpool txPool) {
e.defaultGov.SetTxPool(txpool)
}

func (e *MixedEngine) GetTxPool() txPool {
return e.defaultGov.GetTxPool()
}

func (e *MixedEngine) GovernanceMode() string {
return e.defaultGov.GovernanceMode()
}
Expand Down
7 changes: 3 additions & 4 deletions node/cn/filters/api.go
Original file line number Diff line number Diff line change
Expand Up @@ -233,11 +233,10 @@ func RPCMarshalHeader(head *types.Header, isEnabledEthTxTypeFork bool) map[strin
}

if isEnabledEthTxTypeFork {
if head.BaseFee != nil {
// KIP71 hardforked block
result["baseFeePerGas"] = (*hexutil.Big)(head.BaseFee)
} else {
if head.BaseFee == nil {
result["baseFeePerGas"] = (*hexutil.Big)(new(big.Int).SetUint64(params.ZeroBaseFee))
} else {
result["baseFeePerGas"] = (*hexutil.Big)(head.BaseFee)
}
}

Expand Down
17 changes: 14 additions & 3 deletions node/cn/gasprice/feehistory.go
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ import (

"github.com/klaytn/klaytn/blockchain/types"
"github.com/klaytn/klaytn/common"
"github.com/klaytn/klaytn/consensus/misc"
"github.com/klaytn/klaytn/log"
"github.com/klaytn/klaytn/networks/rpc"
"github.com/klaytn/klaytn/params"
Expand Down Expand Up @@ -90,9 +91,16 @@ func (s sortGasAndReward) Less(i, j int) bool {
func (oracle *Oracle) processBlock(bf *blockFees, percentiles []float64) {
chainconfig := oracle.backend.ChainConfig()
// TODO-Klaytn: If we implement baseFee feature like Ethereum does, we should set it from header, not constant.
bf.results.baseFee = new(big.Int).SetUint64(params.ZeroBaseFee)
if bf.results.baseFee = bf.header.BaseFee; bf.results.baseFee == nil {
bf.results.baseFee = new(big.Int).SetUint64(params.ZeroBaseFee)
}
// TODO-Klaytn: If we implement baseFee feature like Ethereum does, we should calculate nextBaseFee from parent block header.
bf.results.nextBaseFee = new(big.Int).SetUint64(params.ZeroBaseFee)
if chainconfig.IsKIP71ForkEnabled(big.NewInt(int64(bf.blockNumber + 1))) {
bf.results.nextBaseFee = misc.NextBlockBaseFee(bf.header, chainconfig)
} else {
bf.results.nextBaseFee = new(big.Int).SetUint64(params.ZeroBaseFee)
}

// There is no GasLimit in Klaytn, so it is enough to use pre-defined constant in api package as now.
bf.results.gasUsedRatio = float64(bf.header.GasUsed) / float64(params.UpperGasLimit)
if len(percentiles) == 0 {
Expand All @@ -116,7 +124,10 @@ func (oracle *Oracle) processBlock(bf *blockFees, percentiles []float64) {
sorter := make(sortGasAndReward, len(bf.block.Transactions()))
for i := range bf.block.Transactions() {
// TODO-Klaytn: If we change the fixed unit price policy and add baseFee feature, we should re-calculate reward.
reward := new(big.Int).SetUint64(chainconfig.UnitPrice) // As now, reward is always same because the baseFee in Klaytn is 0 and gasPrice is fixed.
reward := bf.block.Header().BaseFee
if reward == nil {
reward = new(big.Int).SetUint64(chainconfig.UnitPrice)
}
sorter[i] = txGasAndReward{gasUsed: bf.receipts[i].GasUsed, reward: reward}
}
sort.Sort(sorter)
Expand Down
0