Merge pull request #3800 from filecoin-project/asr/gascost
Add an API to get detailed gas costs for a message
This commit is contained in:
commit
d4a7732d0a
@ -354,6 +354,8 @@ type FullNode interface {
|
|||||||
StateSectorPartition(ctx context.Context, maddr address.Address, sectorNumber abi.SectorNumber, tok types.TipSetKey) (*SectorLocation, error)
|
StateSectorPartition(ctx context.Context, maddr address.Address, sectorNumber abi.SectorNumber, tok types.TipSetKey) (*SectorLocation, error)
|
||||||
// StateSearchMsg searches for a message in the chain, and returns its receipt and the tipset where it was executed
|
// StateSearchMsg searches for a message in the chain, and returns its receipt and the tipset where it was executed
|
||||||
StateSearchMsg(context.Context, cid.Cid) (*MsgLookup, error)
|
StateSearchMsg(context.Context, cid.Cid) (*MsgLookup, error)
|
||||||
|
// StateMsgGasCost searches for a message in the chain, and returns details of the messages gas costs, including the penalty and miner tip
|
||||||
|
StateMsgGasCost(context.Context, cid.Cid, types.TipSetKey) (*MsgGasCost, error)
|
||||||
// StateWaitMsg looks back in the chain for a message. If not found, it blocks until the
|
// StateWaitMsg looks back in the chain for a message. If not found, it blocks until the
|
||||||
// message arrives on chain, and gets to the indicated confidence depth.
|
// message arrives on chain, and gets to the indicated confidence depth.
|
||||||
StateWaitMsg(ctx context.Context, cid cid.Cid, confidence uint64) (*MsgLookup, error)
|
StateWaitMsg(ctx context.Context, cid cid.Cid, confidence uint64) (*MsgLookup, error)
|
||||||
@ -531,6 +533,17 @@ type MsgLookup struct {
|
|||||||
Height abi.ChainEpoch
|
Height abi.ChainEpoch
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type MsgGasCost struct {
|
||||||
|
Message cid.Cid // Can be different than requested, in case it was replaced, but only gas values changed
|
||||||
|
GasUsed abi.TokenAmount
|
||||||
|
BaseFeeBurn abi.TokenAmount
|
||||||
|
OverEstimationBurn abi.TokenAmount
|
||||||
|
MinerPenalty abi.TokenAmount
|
||||||
|
MinerTip abi.TokenAmount
|
||||||
|
Refund abi.TokenAmount
|
||||||
|
TotalCost abi.TokenAmount
|
||||||
|
}
|
||||||
|
|
||||||
type BlockMessages struct {
|
type BlockMessages struct {
|
||||||
BlsMessages []*types.Message
|
BlsMessages []*types.Message
|
||||||
SecpkMessages []*types.SignedMessage
|
SecpkMessages []*types.SignedMessage
|
||||||
|
@ -183,6 +183,7 @@ type FullNodeStruct struct {
|
|||||||
StateReplay func(context.Context, types.TipSetKey, cid.Cid) (*api.InvocResult, error) `perm:"read"`
|
StateReplay func(context.Context, types.TipSetKey, cid.Cid) (*api.InvocResult, error) `perm:"read"`
|
||||||
StateGetActor func(context.Context, address.Address, types.TipSetKey) (*types.Actor, error) `perm:"read"`
|
StateGetActor func(context.Context, address.Address, types.TipSetKey) (*types.Actor, error) `perm:"read"`
|
||||||
StateReadState func(context.Context, address.Address, types.TipSetKey) (*api.ActorState, error) `perm:"read"`
|
StateReadState func(context.Context, address.Address, types.TipSetKey) (*api.ActorState, error) `perm:"read"`
|
||||||
|
StateMsgGasCost func(context.Context, cid.Cid, types.TipSetKey) (*api.MsgGasCost, error) `perm:"read"`
|
||||||
StateWaitMsg func(ctx context.Context, cid cid.Cid, confidence uint64) (*api.MsgLookup, error) `perm:"read"`
|
StateWaitMsg func(ctx context.Context, cid cid.Cid, confidence uint64) (*api.MsgLookup, error) `perm:"read"`
|
||||||
StateSearchMsg func(context.Context, cid.Cid) (*api.MsgLookup, error) `perm:"read"`
|
StateSearchMsg func(context.Context, cid.Cid) (*api.MsgLookup, error) `perm:"read"`
|
||||||
StateListMiners func(context.Context, types.TipSetKey) ([]address.Address, error) `perm:"read"`
|
StateListMiners func(context.Context, types.TipSetKey) ([]address.Address, error) `perm:"read"`
|
||||||
@ -816,6 +817,10 @@ func (c *FullNodeStruct) StateReadState(ctx context.Context, addr address.Addres
|
|||||||
return c.Internal.StateReadState(ctx, addr, tsk)
|
return c.Internal.StateReadState(ctx, addr, tsk)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (c *FullNodeStruct) StateMsgGasCost(ctx context.Context, msgc cid.Cid, tsk types.TipSetKey) (*api.MsgGasCost, error) {
|
||||||
|
return c.Internal.StateMsgGasCost(ctx, msgc, tsk)
|
||||||
|
}
|
||||||
|
|
||||||
func (c *FullNodeStruct) StateWaitMsg(ctx context.Context, msgc cid.Cid, confidence uint64) (*api.MsgLookup, error) {
|
func (c *FullNodeStruct) StateWaitMsg(ctx context.Context, msgc cid.Cid, confidence uint64) (*api.MsgLookup, error) {
|
||||||
return c.Internal.StateWaitMsg(ctx, msgc, confidence)
|
return c.Internal.StateWaitMsg(ctx, msgc, confidence)
|
||||||
}
|
}
|
||||||
|
@ -29,7 +29,7 @@ func init() {
|
|||||||
BuildType |= Build2k
|
BuildType |= Build2k
|
||||||
}
|
}
|
||||||
|
|
||||||
const BlockDelaySecs = uint64(30)
|
const BlockDelaySecs = uint64(4)
|
||||||
|
|
||||||
const PropagationDelaySecs = uint64(1)
|
const PropagationDelaySecs = uint64(1)
|
||||||
|
|
||||||
|
@ -233,8 +233,8 @@ func (sm *StateManager) ApplyBlocks(ctx context.Context, parentEpoch abi.ChainEp
|
|||||||
}
|
}
|
||||||
|
|
||||||
receipts = append(receipts, &r.MessageReceipt)
|
receipts = append(receipts, &r.MessageReceipt)
|
||||||
gasReward = big.Add(gasReward, r.MinerTip)
|
gasReward = big.Add(gasReward, r.GasCosts.MinerTip)
|
||||||
penalty = big.Add(penalty, r.Penalty)
|
penalty = big.Add(penalty, r.GasCosts.MinerPenalty)
|
||||||
|
|
||||||
if cb != nil {
|
if cb != nil {
|
||||||
if err := cb(cm.Cid(), m, r); err != nil {
|
if err := cb(cm.Cid(), m, r); err != nil {
|
||||||
|
@ -201,10 +201,9 @@ type Rand interface {
|
|||||||
type ApplyRet struct {
|
type ApplyRet struct {
|
||||||
types.MessageReceipt
|
types.MessageReceipt
|
||||||
ActorErr aerrors.ActorError
|
ActorErr aerrors.ActorError
|
||||||
Penalty types.BigInt
|
|
||||||
MinerTip types.BigInt
|
|
||||||
ExecutionTrace types.ExecutionTrace
|
ExecutionTrace types.ExecutionTrace
|
||||||
Duration time.Duration
|
Duration time.Duration
|
||||||
|
GasCosts GasOutputs
|
||||||
}
|
}
|
||||||
|
|
||||||
func (vm *VM) send(ctx context.Context, msg *types.Message, parent *Runtime,
|
func (vm *VM) send(ctx context.Context, msg *types.Message, parent *Runtime,
|
||||||
@ -328,8 +327,7 @@ func (vm *VM) ApplyImplicitMessage(ctx context.Context, msg *types.Message) (*Ap
|
|||||||
},
|
},
|
||||||
ActorErr: actorErr,
|
ActorErr: actorErr,
|
||||||
ExecutionTrace: rt.executionTrace,
|
ExecutionTrace: rt.executionTrace,
|
||||||
Penalty: types.NewInt(0),
|
GasCosts: GasOutputs{},
|
||||||
MinerTip: types.NewInt(0),
|
|
||||||
Duration: time.Since(start),
|
Duration: time.Since(start),
|
||||||
}, actorErr
|
}, actorErr
|
||||||
}
|
}
|
||||||
@ -362,9 +360,10 @@ func (vm *VM) ApplyMessage(ctx context.Context, cmsg types.ChainMsg) (*ApplyRet,
|
|||||||
ExitCode: exitcode.SysErrOutOfGas,
|
ExitCode: exitcode.SysErrOutOfGas,
|
||||||
GasUsed: 0,
|
GasUsed: 0,
|
||||||
},
|
},
|
||||||
Penalty: types.BigMul(vm.baseFee, abi.NewTokenAmount(msgGasCost)),
|
GasCosts: GasOutputs{
|
||||||
|
MinerPenalty: types.BigMul(vm.baseFee, abi.NewTokenAmount(msgGasCost)),
|
||||||
|
},
|
||||||
Duration: time.Since(start),
|
Duration: time.Since(start),
|
||||||
MinerTip: big.Zero(),
|
|
||||||
}, nil
|
}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -381,9 +380,10 @@ func (vm *VM) ApplyMessage(ctx context.Context, cmsg types.ChainMsg) (*ApplyRet,
|
|||||||
GasUsed: 0,
|
GasUsed: 0,
|
||||||
},
|
},
|
||||||
ActorErr: aerrors.Newf(exitcode.SysErrSenderInvalid, "actor not found: %s", msg.From),
|
ActorErr: aerrors.Newf(exitcode.SysErrSenderInvalid, "actor not found: %s", msg.From),
|
||||||
Penalty: minerPenaltyAmount,
|
GasCosts: GasOutputs{
|
||||||
|
MinerPenalty: minerPenaltyAmount,
|
||||||
|
},
|
||||||
Duration: time.Since(start),
|
Duration: time.Since(start),
|
||||||
MinerTip: big.Zero(),
|
|
||||||
}, nil
|
}, nil
|
||||||
}
|
}
|
||||||
return nil, xerrors.Errorf("failed to look up from actor: %w", err)
|
return nil, xerrors.Errorf("failed to look up from actor: %w", err)
|
||||||
@ -397,9 +397,10 @@ func (vm *VM) ApplyMessage(ctx context.Context, cmsg types.ChainMsg) (*ApplyRet,
|
|||||||
GasUsed: 0,
|
GasUsed: 0,
|
||||||
},
|
},
|
||||||
ActorErr: aerrors.Newf(exitcode.SysErrSenderInvalid, "send from not account actor: %s", fromActor.Code),
|
ActorErr: aerrors.Newf(exitcode.SysErrSenderInvalid, "send from not account actor: %s", fromActor.Code),
|
||||||
Penalty: minerPenaltyAmount,
|
GasCosts: GasOutputs{
|
||||||
|
MinerPenalty: minerPenaltyAmount,
|
||||||
|
},
|
||||||
Duration: time.Since(start),
|
Duration: time.Since(start),
|
||||||
MinerTip: big.Zero(),
|
|
||||||
}, nil
|
}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -411,9 +412,11 @@ func (vm *VM) ApplyMessage(ctx context.Context, cmsg types.ChainMsg) (*ApplyRet,
|
|||||||
},
|
},
|
||||||
ActorErr: aerrors.Newf(exitcode.SysErrSenderStateInvalid,
|
ActorErr: aerrors.Newf(exitcode.SysErrSenderStateInvalid,
|
||||||
"actor nonce invalid: msg:%d != state:%d", msg.Nonce, fromActor.Nonce),
|
"actor nonce invalid: msg:%d != state:%d", msg.Nonce, fromActor.Nonce),
|
||||||
Penalty: minerPenaltyAmount,
|
|
||||||
|
GasCosts: GasOutputs{
|
||||||
|
MinerPenalty: minerPenaltyAmount,
|
||||||
|
},
|
||||||
Duration: time.Since(start),
|
Duration: time.Since(start),
|
||||||
MinerTip: big.Zero(),
|
|
||||||
}, nil
|
}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -426,9 +429,10 @@ func (vm *VM) ApplyMessage(ctx context.Context, cmsg types.ChainMsg) (*ApplyRet,
|
|||||||
},
|
},
|
||||||
ActorErr: aerrors.Newf(exitcode.SysErrSenderStateInvalid,
|
ActorErr: aerrors.Newf(exitcode.SysErrSenderStateInvalid,
|
||||||
"actor balance less than needed: %s < %s", types.FIL(fromActor.Balance), types.FIL(gascost)),
|
"actor balance less than needed: %s < %s", types.FIL(fromActor.Balance), types.FIL(gascost)),
|
||||||
Penalty: minerPenaltyAmount,
|
GasCosts: GasOutputs{
|
||||||
|
MinerPenalty: minerPenaltyAmount,
|
||||||
|
},
|
||||||
Duration: time.Since(start),
|
Duration: time.Since(start),
|
||||||
MinerTip: big.Zero(),
|
|
||||||
}, nil
|
}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -521,8 +525,7 @@ func (vm *VM) ApplyMessage(ctx context.Context, cmsg types.ChainMsg) (*ApplyRet,
|
|||||||
},
|
},
|
||||||
ActorErr: actorErr,
|
ActorErr: actorErr,
|
||||||
ExecutionTrace: rt.executionTrace,
|
ExecutionTrace: rt.executionTrace,
|
||||||
Penalty: gasOutputs.MinerPenalty,
|
GasCosts: gasOutputs,
|
||||||
MinerTip: gasOutputs.MinerTip,
|
|
||||||
Duration: time.Since(start),
|
Duration: time.Since(start),
|
||||||
}, nil
|
}, nil
|
||||||
}
|
}
|
||||||
|
55
cli/state.go
55
cli/state.go
@ -66,6 +66,7 @@ var stateCmd = &cli.Command{
|
|||||||
stateGetDealSetCmd,
|
stateGetDealSetCmd,
|
||||||
stateWaitMsgCmd,
|
stateWaitMsgCmd,
|
||||||
stateSearchMsgCmd,
|
stateSearchMsgCmd,
|
||||||
|
stateMsgCostCmd,
|
||||||
stateMinerInfo,
|
stateMinerInfo,
|
||||||
stateMarketCmd,
|
stateMarketCmd,
|
||||||
},
|
},
|
||||||
@ -1312,6 +1313,60 @@ var stateSearchMsgCmd = &cli.Command{
|
|||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var stateMsgCostCmd = &cli.Command{
|
||||||
|
Name: "msg-cost",
|
||||||
|
Usage: "Get the detailed gas costs of a message",
|
||||||
|
ArgsUsage: "[messageCid]",
|
||||||
|
Action: func(cctx *cli.Context) error {
|
||||||
|
if !cctx.Args().Present() {
|
||||||
|
return fmt.Errorf("must specify message cid to get gas costs for")
|
||||||
|
}
|
||||||
|
|
||||||
|
api, closer, err := GetFullNodeAPI(cctx)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
defer closer()
|
||||||
|
|
||||||
|
ctx := ReqContext(cctx)
|
||||||
|
|
||||||
|
msg, err := cid.Decode(cctx.Args().First())
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
tsk := types.EmptyTSK
|
||||||
|
|
||||||
|
ts, err := LoadTipSet(ctx, cctx, api)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
if ts != nil {
|
||||||
|
tsk = ts.Key()
|
||||||
|
}
|
||||||
|
|
||||||
|
mgc, err := api.StateMsgGasCost(ctx, msg, tsk)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
if mgc != nil {
|
||||||
|
fmt.Printf("Message CID: %s", mgc.Message)
|
||||||
|
fmt.Printf("\nGas Used: %d", mgc.GasUsed)
|
||||||
|
fmt.Printf("\nBase Fee Burn: %d", mgc.BaseFeeBurn)
|
||||||
|
fmt.Printf("\nOverestimation Burn: %d", mgc.OverEstimationBurn)
|
||||||
|
fmt.Printf("\nMiner Tip: %d", mgc.MinerTip)
|
||||||
|
fmt.Printf("\nRefund: %d", mgc.Refund)
|
||||||
|
fmt.Printf("\nTotal Cost: %d", mgc.TotalCost)
|
||||||
|
fmt.Printf("\nMiner Penalty: %d", mgc.MinerPenalty)
|
||||||
|
} else {
|
||||||
|
fmt.Print("message was not found on chain")
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
var stateCallCmd = &cli.Command{
|
var stateCallCmd = &cli.Command{
|
||||||
Name: "call",
|
Name: "call",
|
||||||
Usage: "Invoke a method on an actor locally",
|
Usage: "Invoke a method on an actor locally",
|
||||||
|
@ -148,6 +148,7 @@
|
|||||||
* [StateMinerRecoveries](#StateMinerRecoveries)
|
* [StateMinerRecoveries](#StateMinerRecoveries)
|
||||||
* [StateMinerSectorCount](#StateMinerSectorCount)
|
* [StateMinerSectorCount](#StateMinerSectorCount)
|
||||||
* [StateMinerSectors](#StateMinerSectors)
|
* [StateMinerSectors](#StateMinerSectors)
|
||||||
|
* [StateMsgGasCost](#StateMsgGasCost)
|
||||||
* [StateNetworkName](#StateNetworkName)
|
* [StateNetworkName](#StateNetworkName)
|
||||||
* [StateReadState](#StateReadState)
|
* [StateReadState](#StateReadState)
|
||||||
* [StateReplay](#StateReplay)
|
* [StateReplay](#StateReplay)
|
||||||
@ -3737,6 +3738,45 @@ Inputs:
|
|||||||
|
|
||||||
Response: `null`
|
Response: `null`
|
||||||
|
|
||||||
|
### StateMsgGasCost
|
||||||
|
StateMsgGasCost searches for a message in the chain, and returns details of the messages gas costs, including the penalty and miner tip
|
||||||
|
|
||||||
|
|
||||||
|
Perms: read
|
||||||
|
|
||||||
|
Inputs:
|
||||||
|
```json
|
||||||
|
[
|
||||||
|
{
|
||||||
|
"/": "bafy2bzacea3wsdh6y3a36tb3skempjoxqpuyompjbmfeyf34fi3uy6uue42v4"
|
||||||
|
},
|
||||||
|
[
|
||||||
|
{
|
||||||
|
"/": "bafy2bzacea3wsdh6y3a36tb3skempjoxqpuyompjbmfeyf34fi3uy6uue42v4"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"/": "bafy2bzacebp3shtrn43k7g3unredz7fxn4gj533d3o43tqn2p2ipxxhrvchve"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
]
|
||||||
|
```
|
||||||
|
|
||||||
|
Response:
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"Message": {
|
||||||
|
"/": "bafy2bzacea3wsdh6y3a36tb3skempjoxqpuyompjbmfeyf34fi3uy6uue42v4"
|
||||||
|
},
|
||||||
|
"GasUsed": "0",
|
||||||
|
"BaseFeeBurn": "0",
|
||||||
|
"OverEstimationBurn": "0",
|
||||||
|
"MinerPenalty": "0",
|
||||||
|
"MinerTip": "0",
|
||||||
|
"Refund": "0",
|
||||||
|
"TotalCost": "0"
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
### StateNetworkName
|
### StateNetworkName
|
||||||
StateNetworkName returns the name of the network the node is synced to
|
StateNetworkName returns the name of the network the node is synced to
|
||||||
|
|
||||||
|
2
extern/storage-sealing/upgrade_queue.go
vendored
2
extern/storage-sealing/upgrade_queue.go
vendored
@ -67,6 +67,8 @@ func (m *Sealing) tryUpgradeSector(ctx context.Context, params *miner.SectorPreC
|
|||||||
params.ReplaceSectorDeadline = loc.Deadline
|
params.ReplaceSectorDeadline = loc.Deadline
|
||||||
params.ReplaceSectorPartition = loc.Partition
|
params.ReplaceSectorPartition = loc.Partition
|
||||||
|
|
||||||
|
log.Infof("replacing sector %d with %d", *replace, params.SectorNumber)
|
||||||
|
|
||||||
ri, err := m.api.StateSectorGetInfo(ctx, m.maddr, *replace, nil)
|
ri, err := m.api.StateSectorGetInfo(ctx, m.maddr, *replace, nil)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Errorf("error calling StateSectorGetInfo for replaced sector: %+v", err)
|
log.Errorf("error calling StateSectorGetInfo for replaced sector: %+v", err)
|
||||||
|
@ -1225,3 +1225,52 @@ func (a *StateAPI) StateCirculatingSupply(ctx context.Context, tsk types.TipSetK
|
|||||||
|
|
||||||
return a.StateManager.GetCirculatingSupplyDetailed(ctx, ts.Height(), sTree)
|
return a.StateManager.GetCirculatingSupplyDetailed(ctx, ts.Height(), sTree)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (a *StateAPI) StateMsgGasCost(ctx context.Context, inputMsg cid.Cid, tsk types.TipSetKey) (*api.MsgGasCost, error) {
|
||||||
|
var msg cid.Cid
|
||||||
|
var ts *types.TipSet
|
||||||
|
var err error
|
||||||
|
if tsk != types.EmptyTSK {
|
||||||
|
msg = inputMsg
|
||||||
|
ts, err = a.Chain.LoadTipSet(tsk)
|
||||||
|
if err != nil {
|
||||||
|
return nil, xerrors.Errorf("loading tipset %s: %w", tsk, err)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
mlkp, err := a.StateSearchMsg(ctx, inputMsg)
|
||||||
|
if err != nil {
|
||||||
|
return nil, xerrors.Errorf("searching for msg %s: %w", inputMsg, err)
|
||||||
|
}
|
||||||
|
if mlkp == nil {
|
||||||
|
return nil, xerrors.Errorf("didn't find msg %s", inputMsg)
|
||||||
|
}
|
||||||
|
|
||||||
|
executionTs, err := a.Chain.GetTipSetFromKey(mlkp.TipSet)
|
||||||
|
if err != nil {
|
||||||
|
return nil, xerrors.Errorf("loading tipset %s: %w", mlkp.TipSet, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
ts, err = a.Chain.LoadTipSet(executionTs.Parents())
|
||||||
|
if err != nil {
|
||||||
|
return nil, xerrors.Errorf("loading parent tipset %s: %w", mlkp.TipSet, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
msg = mlkp.Message
|
||||||
|
}
|
||||||
|
|
||||||
|
m, r, err := a.StateManager.Replay(ctx, ts, msg)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return &api.MsgGasCost{
|
||||||
|
Message: msg,
|
||||||
|
GasUsed: big.NewInt(r.GasUsed),
|
||||||
|
BaseFeeBurn: r.GasCosts.BaseFeeBurn,
|
||||||
|
OverEstimationBurn: r.GasCosts.OverEstimationBurn,
|
||||||
|
MinerPenalty: r.GasCosts.MinerPenalty,
|
||||||
|
MinerTip: r.GasCosts.MinerTip,
|
||||||
|
Refund: r.GasCosts.Refund,
|
||||||
|
TotalCost: big.Sub(m.RequiredFunds(), r.GasCosts.Refund),
|
||||||
|
}, nil
|
||||||
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user