Skip to content

Commit

Permalink
Merge pull request #289 from ethstorage/miner_opt1
Browse files Browse the repository at this point in the history
Fix `max fee per gas less than block base fee`
  • Loading branch information
syntrust authored Oct 11, 2024
2 parents b374c27 + b8c53d5 commit 1cec4d6
Show file tree
Hide file tree
Showing 3 changed files with 93 additions and 65 deletions.
145 changes: 84 additions & 61 deletions ethstorage/miner/l1_mining_api.go
Original file line number Diff line number Diff line change
Expand Up @@ -85,65 +85,22 @@ func (m *l1MiningAPI) GetDataHashes(ctx context.Context, contract common.Address

func (m *l1MiningAPI) SubmitMinedResult(ctx context.Context, contract common.Address, rst result, cfg Config) (common.Hash, error) {
m.lg.Debug("Submit mined result", "shard", rst.startShardId, "block", rst.blockNumber, "nonce", rst.nonce)
headerRlp, err := m.getRandaoProof(ctx, rst.blockNumber)
calldata, err := m.composeCalldata(ctx, rst)
if err != nil {
m.lg.Error("Failed to get randao proof", "error", err)
m.lg.Error("Failed to compose calldata", "error", err)
return common.Hash{}, err
}
uint256Type, _ := abi.NewType("uint256", "", nil)
uint256Array, _ := abi.NewType("uint256[]", "", nil)
addrType, _ := abi.NewType("address", "", nil)
bytes32Array, _ := abi.NewType("bytes32[]", "", nil)
bytesArray, _ := abi.NewType("bytes[]", "", nil)
bytesType, _ := abi.NewType("bytes", "", nil)
dataField, _ := abi.Arguments{
{Type: uint256Type},
{Type: uint256Type},
{Type: addrType},
{Type: uint256Type},
{Type: bytes32Array},
{Type: uint256Array},
{Type: bytesType},
{Type: bytesArray},
{Type: bytesArray},
}.Pack(
rst.blockNumber,
new(big.Int).SetUint64(rst.startShardId),
rst.miner,
new(big.Int).SetUint64(rst.nonce),
rst.encodedData,
rst.masks,
headerRlp,
rst.inclusiveProofs,
rst.decodeProof,
)
calldata := append(mineSig[0:4], dataField...)
m.lg.Debug("Submit mined result", "calldata", common.Bytes2Hex(calldata))
gasPrice := cfg.GasPrice
if gasPrice == nil || gasPrice.Cmp(common.Big0) == 0 {
suggested, err := m.SuggestGasPrice(ctx)
if err != nil {
m.lg.Error("Query gas price failed", "error", err.Error())
return common.Hash{}, err
}
gasPrice = suggested
m.lg.Info("Query gas price done", "gasPrice", gasPrice)
}
tip := cfg.PriorityGasPrice
if tip == nil || tip.Cmp(common.Big0) == 0 {
suggested, err := m.SuggestGasTipCap(ctx)
if err != nil {
m.lg.Error("Query gas tip cap failed", "error", err.Error())
suggested = common.Big0
}
tip = suggested
m.lg.Info("Query gas tip cap done", "gasTipGap", tip)

tip, gasFeeCap, useConfig, err := m.suggestGasPrices(ctx, cfg)
if err != nil {
m.lg.Error("Failed to suggest gas prices", "error", err)
return common.Hash{}, err
}
estimatedGas, err := m.EstimateGas(ctx, ethereum.CallMsg{
From: cfg.SignerAddr,
To: &contract,
GasTipCap: tip,
GasFeeCap: gasPrice,
GasFeeCap: gasFeeCap,
Value: common.Big0,
Data: calldata,
})
Expand All @@ -152,21 +109,23 @@ func (m *l1MiningAPI) SubmitMinedResult(ctx context.Context, contract common.Add
return common.Hash{}, fmt.Errorf("failed to estimate gas: %w", err)
}
m.lg.Info("Estimated gas done", "gas", estimatedGas)
cost := new(big.Int).Mul(new(big.Int).SetUint64(estimatedGas), gasPrice)

reward, err := m.GetMiningReward(rst.startShardId, rst.blockNumber.Int64())
if err != nil {
m.lg.Error("Query mining reward failed", "error", err.Error())
return common.Hash{}, err
}
profit := new(big.Int).Sub(reward, cost)
m.lg.Info("Estimated reward and cost (in ether)", "reward", weiToEther(reward), "cost", weiToEther(cost), "profit", weiToEther(profit))
if profit.Cmp(cfg.MinimumProfit) == -1 {
m.lg.Warn("Will drop the tx: the profit will not meet expectation",
"profitEstimated", weiToEther(profit),
"minimumProfit", weiToEther(cfg.MinimumProfit),
)
profitableGasFeeCap := new(big.Int).Div(new(big.Int).Sub(reward, cfg.MinimumProfit), new(big.Int).SetUint64(estimatedGas))
m.lg.Info("Minimum profitable gas fee cap", "gasFeeCap", profitableGasFeeCap)
if gasFeeCap.Cmp(profitableGasFeeCap) == 1 {
profit := new(big.Int).Sub(reward, new(big.Int).Mul(new(big.Int).SetUint64(estimatedGas), gasFeeCap))
m.lg.Warn("Mining tx dropped: the profit will not meet expectation", "estimatedProfit", fmtEth(profit), "minimumProfit", fmtEth(cfg.MinimumProfit))
return common.Hash{}, errDropped
}
if !useConfig {
gasFeeCap = profitableGasFeeCap
m.lg.Info("Using profitable gas fee cap", "gasFeeCap", gasFeeCap)
}
sign := cfg.SignerFnFactory(m.NetworkID)
nonce, err := m.NonceAt(ctx, cfg.SignerAddr, big.NewInt(rpc.LatestBlockNumber.Int64()))
if err != nil {
Expand All @@ -179,7 +138,7 @@ func (m *l1MiningAPI) SubmitMinedResult(ctx context.Context, contract common.Add
ChainID: m.NetworkID,
Nonce: nonce,
GasTipCap: tip,
GasFeeCap: gasPrice,
GasFeeCap: gasFeeCap,
Gas: gas,
To: &contract,
Value: common.Big0,
Expand All @@ -192,7 +151,7 @@ func (m *l1MiningAPI) SubmitMinedResult(ctx context.Context, contract common.Add
}
err = m.SendTransaction(ctx, signedTx)
if err != nil {
m.lg.Error("Send tx failed", "txNonce", nonce, "gasPrice", gasPrice, "error", err)
m.lg.Error("Send tx failed", "txNonce", nonce, "gasFeeCap", gasFeeCap, "error", err)
return common.Hash{}, err
}
m.lg.Info("Submit mined result done", "shard", rst.startShardId, "block", rst.blockNumber,
Expand Down Expand Up @@ -221,3 +180,67 @@ func (m *l1MiningAPI) getRandaoProof(ctx context.Context, blockNumber *big.Int)
}
return headerRlp, nil
}

func (m *l1MiningAPI) composeCalldata(ctx context.Context, rst result) ([]byte, error) {
headerRlp, err := m.getRandaoProof(ctx, rst.blockNumber)
if err != nil {
m.lg.Error("Failed to get randao proof", "error", err)
return nil, err
}
uint256Type, _ := abi.NewType("uint256", "", nil)
uint256Array, _ := abi.NewType("uint256[]", "", nil)
addrType, _ := abi.NewType("address", "", nil)
bytes32Array, _ := abi.NewType("bytes32[]", "", nil)
bytesArray, _ := abi.NewType("bytes[]", "", nil)
bytesType, _ := abi.NewType("bytes", "", nil)
dataField, _ := abi.Arguments{
{Type: uint256Type},
{Type: uint256Type},
{Type: addrType},
{Type: uint256Type},
{Type: bytes32Array},
{Type: uint256Array},
{Type: bytesType},
{Type: bytesArray},
{Type: bytesArray},
}.Pack(
rst.blockNumber,
new(big.Int).SetUint64(rst.startShardId),
rst.miner,
new(big.Int).SetUint64(rst.nonce),
rst.encodedData,
rst.masks,
headerRlp,
rst.inclusiveProofs,
rst.decodeProof,
)
calldata := append(mineSig[0:4], dataField...)
return calldata, nil
}

func (m *l1MiningAPI) suggestGasPrices(ctx context.Context, cfg Config) (*big.Int, *big.Int, bool, error) {
gasFeeCap := cfg.GasPrice
tip := cfg.PriorityGasPrice
useConfig := true
if gasFeeCap == nil || gasFeeCap.Cmp(common.Big0) == 0 {
useConfig = false
blockHeader, err := m.HeaderByNumber(ctx, nil)
if err != nil {
m.lg.Error("Failed to get block header", "error", err)
return nil, nil, false, err
}
m.lg.Info("Query baseFee done", "baseFee", blockHeader.BaseFee)
if tip == nil || tip.Cmp(common.Big0) == 0 {
suggested, err := m.SuggestGasTipCap(ctx)
if err != nil {
m.lg.Error("Query gas tip cap failed", "error", err.Error())
suggested = common.Big0
}
tip = suggested
m.lg.Info("Query gas tip cap done", "gasTipGap", tip)
}
gasFeeCap = new(big.Int).Add(blockHeader.BaseFee, tip)
m.lg.Info("Suggested gas fee cap", "gasFeeCap", gasFeeCap)
}
return tip, gasFeeCap, useConfig, nil
}
11 changes: 8 additions & 3 deletions ethstorage/miner/worker.go
Original file line number Diff line number Diff line change
Expand Up @@ -487,9 +487,9 @@ func (w *worker) checkTxStatus(txHash common.Hash, miner common.Address) {
}
if reward != nil {
log.Info("Mining transaction accounting (in ether)",
"reward", weiToEther(reward),
"cost", weiToEther(cost),
"profit", weiToEther(new(big.Int).Sub(reward, cost)),
"reward", fmtEth(reward),
"cost", fmtEth(cost),
"profit", fmtEth(new(big.Int).Sub(reward, cost)),
)
}
} else if receipt.Status == 0 {
Expand All @@ -511,6 +511,11 @@ func weiToEther(wei *big.Int) *big.Float {
return f.Quo(fWei.SetInt(wei), big.NewFloat(params.Ether))
}

func fmtEth(wei *big.Int) string {
f := weiToEther(wei)
return fmt.Sprintf("%.9f", f)
}

// mineTask actually executes a mining task
func (w *worker) mineTask(t *taskItem) (bool, error) {
startTime := time.Now()
Expand Down
2 changes: 1 addition & 1 deletion integration_tests/node_mine_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -432,7 +432,7 @@ func initMiningConfig(t *testing.T, client *eth.PollingClient) *miner.Config {
miningConfig.ZKProverMode = 2
miningConfig.ZKProverImpl = 2
miningConfig.ThreadsPerShard = 2
miningConfig.MinimumProfit = new(big.Int).SetInt64(-1e18)
miningConfig.MinimumProfit = new(big.Int).SetInt64(-500000000000)
return miningConfig
}

Expand Down

0 comments on commit 1cec4d6

Please sign in to comment.