diff --git a/ethstorage/miner/l1_mining_api.go b/ethstorage/miner/l1_mining_api.go index 5bea0d10..fd6601e5 100644 --- a/ethstorage/miner/l1_mining_api.go +++ b/ethstorage/miner/l1_mining_api.go @@ -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, }) @@ -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 { @@ -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, @@ -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, @@ -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 +} diff --git a/ethstorage/miner/worker.go b/ethstorage/miner/worker.go index b2c239f7..55e55b6f 100644 --- a/ethstorage/miner/worker.go +++ b/ethstorage/miner/worker.go @@ -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 { @@ -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() diff --git a/integration_tests/node_mine_test.go b/integration_tests/node_mine_test.go index 23c60a5c..cab2dd4e 100644 --- a/integration_tests/node_mine_test.go +++ b/integration_tests/node_mine_test.go @@ -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 }