Split precommit batches if gas used exceeds block limit

This commit is contained in:
Shrenuj Bansal 2023-04-10 14:52:39 -04:00
parent da6b565dc1
commit 1e25d7b453
4 changed files with 58 additions and 13 deletions

View File

@ -384,10 +384,13 @@ func gasEstimateGasLimit(
func (m *GasModule) GasEstimateMessageGas(ctx context.Context, msg *types.Message, spec *api.MessageSendSpec, _ types.TipSetKey) (*types.Message, error) {
if msg.GasLimit == 0 {
gasLimit, err := m.GasEstimateGasLimit(ctx, msg, types.EmptyTSK)
log.Errorf("GasEstimateMessageGas GasLimit: %f", gasLimit)
if err != nil {
return nil, err
}
msg.GasLimit = int64(float64(gasLimit) * m.Mpool.GetConfig().GasLimitOverestimation)
log.Errorf("GasEstimateMessageGas GasLimit: %f, GasLimitWithOverestimation", gasLimit, msg.GasLimit)
// Gas overestimation can cause us to exceed the block gas limit, cap it.
if msg.GasLimit > build.BlockGasLimit {
msg.GasLimit = build.BlockGasLimit

View File

@ -31,6 +31,7 @@ import (
type PreCommitBatcherApi interface {
MpoolPushMessage(context.Context, *types.Message, *api.MessageSendSpec) (*types.SignedMessage, error)
GasEstimateMessageGas(context.Context, *types.Message, *api.MessageSendSpec, types.TipSetKey) (*types.Message, error)
StateMinerInfo(context.Context, address.Address, types.TipSetKey) (api.MinerInfo, error)
StateMinerAvailableBalance(context.Context, address.Address, types.TipSetKey) (big.Int, error)
ChainHead(ctx context.Context) (*types.TipSet, error)
@ -319,17 +320,13 @@ func (b *PreCommitBatcher) processSingle(cfg sealiface.Config, mi api.MinerInfo,
return mcid, nil
}
func (b *PreCommitBatcher) processBatch(cfg sealiface.Config, tsk types.TipSetKey, bf abi.TokenAmount, nv network.Version) ([]sealiface.PreCommitBatchRes, error) {
func (b *PreCommitBatcher) processPreCommitBatch(cfg sealiface.Config, bf abi.TokenAmount, entries []*preCommitEntry, nv network.Version) ([]sealiface.PreCommitBatchRes, error) {
log.Errorf("!!!!!!!!!!!!!!!!processPreCommitBatch: %d entries!!!!!!!!!!!!!!!!", len(entries))
params := miner.PreCommitSectorBatchParams{}
deposit := big.Zero()
var res sealiface.PreCommitBatchRes
for _, p := range b.todo {
if len(params.Sectors) >= cfg.MaxPreCommitBatch {
log.Infow("precommit batch full")
break
}
for _, p := range entries {
res.Sectors = append(res.Sectors, p.pci.SectorNumber)
params.Sectors = append(params.Sectors, *infoToPreCommitSectorParams(p.pci))
deposit = big.Add(deposit, p.deposit)
@ -368,18 +365,47 @@ func (b *PreCommitBatcher) processBatch(cfg sealiface.Config, tsk types.TipSetKe
return []sealiface.PreCommitBatchRes{res}, xerrors.Errorf("no good address found: %w", err)
}
mcid, err := sendMsg(b.mctx, b.api, from, b.maddr, builtin.MethodsMiner.PreCommitSectorBatch, needFunds, maxFee, enc.Bytes())
if err != nil {
return []sealiface.PreCommitBatchRes{res}, xerrors.Errorf("sending message failed: %w", err)
msg, err := simulateMsgGas(b.mctx, b.api, from, b.maddr, builtin.MethodsMiner.PreCommitSectorBatch, deposit, maxFee, enc.Bytes())
var gasLimit int64
if msg != nil {
gasLimit = msg.GasLimit
}
log.Errorf("!!!!!!!!!!!!!!simulate Msg err: %w, gasLimit: %d !!!!!!!!!!!!!!!!!!!!", err, gasLimit)
if err != nil && (!api.ErrorIsIn(err, []error{&api.ErrOutOfGas{}}) || len(entries) == 1) {
res.Error = err.Error()
return []sealiface.PreCommitBatchRes{res}, xerrors.Errorf("simulating PreCommitBatch message failed: %w", err)
}
// If we're out of gas, split the batch in half and try again
if api.ErrorIsIn(err, []error{&api.ErrOutOfGas{}}) {
mid := len(entries) / 2
ret0, err := b.processPreCommitBatch(cfg, bf, entries[:mid], nv)
ret1, err := b.processPreCommitBatch(cfg, bf, entries[mid:], nv)
return append(ret0, ret1...), err
}
// If state call succeeds, we can send the message for real
mcid, err := sendMsg(b.mctx, b.api, from, b.maddr, builtin.MethodsMiner.PreCommitSectorBatch, deposit, maxFee, enc.Bytes())
log.Errorf("!!!!!!!!!!!!!!sendMsg err: %w, mcid: %v!!!!!!!!!!!!!!!!!!!!", err, mcid)
if err != nil {
res.Error = err.Error()
return []sealiface.PreCommitBatchRes{res}, xerrors.Errorf("pushing message to mpool: %w", err)
}
res.Msg = &mcid
log.Infow("Sent PreCommitSectorBatch message", "cid", mcid, "from", from, "sectors", len(b.todo))
return []sealiface.PreCommitBatchRes{res}, nil
}
func (b *PreCommitBatcher) processBatch(cfg sealiface.Config, tsk types.TipSetKey, bf abi.TokenAmount, nv network.Version) ([]sealiface.PreCommitBatchRes, error) {
var pcEntries []*preCommitEntry
for _, p := range b.todo {
pcEntries = append(pcEntries, p)
}
return b.processPreCommitBatch(cfg, bf, pcEntries, nv)
}
// register PreCommit, wait for batch message, return message CID
func (b *PreCommitBatcher) AddPreCommit(ctx context.Context, s SectorInfo, deposit abi.TokenAmount, in *miner.SectorPreCommitInfo) (res sealiface.PreCommitBatchRes, err error) {
ts, err := b.api.ChainHead(b.mctx)

View File

@ -64,6 +64,7 @@ type SealingAPI interface {
StateMinerDeadlines(context.Context, address.Address, types.TipSetKey) ([]api.Deadline, error)
StateMinerPartitions(ctx context.Context, m address.Address, dlIdx uint64, tsk types.TipSetKey) ([]api.Partition, error)
MpoolPushMessage(context.Context, *types.Message, *api.MessageSendSpec) (*types.SignedMessage, error)
GasEstimateMessageGas(context.Context, *types.Message, *api.MessageSendSpec, types.TipSetKey) (*types.Message, error)
ChainHead(ctx context.Context) (*types.TipSet, error)
ChainGetMessage(ctx context.Context, mc cid.Cid) (*types.Message, error)
StateGetRandomnessFromBeacon(ctx context.Context, personalization crypto.DomainSeparationTag, randEpoch abi.ChainEpoch, entropy []byte, tsk types.TipSetKey) (abi.Randomness, error)

View File

@ -94,6 +94,21 @@ func collateralSendAmount(ctx context.Context, api interface {
return collateral, nil
}
func simulateMsgGas(ctx context.Context, sa interface {
GasEstimateMessageGas(context.Context, *types.Message, *api.MessageSendSpec, types.TipSetKey) (*types.Message, error)
},
from, to address.Address, method abi.MethodNum, value, maxFee abi.TokenAmount, params []byte) (*types.Message, error) {
msg := types.Message{
To: to,
From: from,
Value: value,
Method: method,
Params: params,
}
return sa.GasEstimateMessageGas(ctx, &msg, nil, types.EmptyTSK)
}
func sendMsg(ctx context.Context, sa interface {
MpoolPushMessage(context.Context, *types.Message, *api.MessageSendSpec) (*types.SignedMessage, error)
}, from, to address.Address, method abi.MethodNum, value, maxFee abi.TokenAmount, params []byte) (cid.Cid, error) {