Rework gas charging
This commit is contained in:
parent
825a3e1d5c
commit
ae40654907
141
chain/vm/gas.go
Normal file
141
chain/vm/gas.go
Normal file
@ -0,0 +1,141 @@
|
||||
package vm
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
addr "github.com/filecoin-project/go-address"
|
||||
"github.com/filecoin-project/specs-actors/actors/abi"
|
||||
"github.com/filecoin-project/specs-actors/actors/crypto"
|
||||
"github.com/filecoin-project/specs-actors/actors/runtime"
|
||||
vmr "github.com/filecoin-project/specs-actors/actors/runtime"
|
||||
"github.com/ipfs/go-cid"
|
||||
)
|
||||
|
||||
// Pricelist provides prices for operations in the VM.
|
||||
//
|
||||
// Note: this interface should be APPEND ONLY since last chain checkpoint
|
||||
type Pricelist interface {
|
||||
// OnChainMessage returns the gas used for storing a message of a given size in the chain.
|
||||
OnChainMessage(msgSize int) int64
|
||||
// OnChainReturnValue returns the gas used for storing the response of a message in the chain.
|
||||
OnChainReturnValue(dataSize int) int64
|
||||
|
||||
// OnMethodInvocation returns the gas used when invoking a method.
|
||||
OnMethodInvocation(value abi.TokenAmount, methodNum abi.MethodNum) int64
|
||||
|
||||
// OnIpldGet returns the gas used for storing an object
|
||||
OnIpldGet(dataSize int) int64
|
||||
// OnIpldPut returns the gas used for storing an object
|
||||
OnIpldPut(dataSize int) int64
|
||||
|
||||
// OnCreateActor returns the gas used for creating an actor
|
||||
OnCreateActor() int64
|
||||
// OnDeleteActor returns the gas used for deleting an actor
|
||||
OnDeleteActor() int64
|
||||
|
||||
OnVerifySignature(sigType crypto.SigType, planTextSize int) int64
|
||||
OnHashing(dataSize int) int64
|
||||
OnComputeUnsealedSectorCid(proofType abi.RegisteredProof, pieces []abi.PieceInfo) int64
|
||||
OnVerifySeal(info abi.SealVerifyInfo) int64
|
||||
OnVerifyPost(info abi.PoStVerifyInfo) int64
|
||||
OnVerifyConsensusFault() int64
|
||||
}
|
||||
|
||||
var prices = map[abi.ChainEpoch]Pricelist{
|
||||
abi.ChainEpoch(0): &pricelistV0{
|
||||
onChainMessageBase: 0,
|
||||
onChainMessagePerByte: 2,
|
||||
onChainReturnValuePerByte: 8,
|
||||
sendBase: 5,
|
||||
sendTransferFunds: 5,
|
||||
sendInvokeMethod: 10,
|
||||
ipldGetBase: 10,
|
||||
ipldGetPerByte: 1,
|
||||
ipldPutBase: 20,
|
||||
ipldPutPerByte: 2,
|
||||
createActorBase: 40, // IPLD put + 20
|
||||
createActorExtra: 500,
|
||||
deleteActor: -500, // -createActorExtra
|
||||
// Dragons: this cost is not persistable, create a LinearCost{a,b} struct that has a `.Cost(x) -> ax + b`
|
||||
verifySignature: map[crypto.SigType]func(int64) int64{
|
||||
crypto.SigTypeBLS: func(x int64) int64 { return 3*x + 2 },
|
||||
crypto.SigTypeSecp256k1: func(x int64) int64 { return 3*x + 2 },
|
||||
},
|
||||
hashingBase: 5,
|
||||
hashingPerByte: 2,
|
||||
computeUnsealedSectorCidBase: 100,
|
||||
verifySealBase: 2000,
|
||||
verifyPostBase: 700,
|
||||
verifyConsensusFault: 10,
|
||||
},
|
||||
}
|
||||
|
||||
// PricelistByEpoch finds the latest prices for the given epoch
|
||||
func PricelistByEpoch(epoch abi.ChainEpoch) Pricelist {
|
||||
// since we are storing the prices as map or epoch to price
|
||||
// we need to get the price with the highest epoch that is lower or equal to the `epoch` arg
|
||||
bestEpoch := abi.ChainEpoch(0)
|
||||
bestPrice := prices[bestEpoch]
|
||||
for e, pl := range prices {
|
||||
// if `e` happened after `bestEpoch` and `e` is earlier or equal to the target `epoch`
|
||||
if e > bestEpoch && e <= epoch {
|
||||
bestEpoch = e
|
||||
bestPrice = pl
|
||||
}
|
||||
}
|
||||
if bestPrice == nil {
|
||||
panic(fmt.Sprintf("bad setup: no gas prices available for epoch %d", epoch))
|
||||
}
|
||||
return bestPrice
|
||||
}
|
||||
|
||||
type pricedSyscalls struct {
|
||||
under vmr.Syscalls
|
||||
pl Pricelist
|
||||
chargeGas func(int64)
|
||||
}
|
||||
|
||||
// Verifies that a signature is valid for an address and plaintext.
|
||||
func (ps pricedSyscalls) VerifySignature(signature crypto.Signature, signer addr.Address, plaintext []byte) error {
|
||||
ps.chargeGas(ps.pl.OnVerifySignature(signature.Type, len(plaintext)))
|
||||
return ps.under.VerifySignature(signature, signer, plaintext)
|
||||
}
|
||||
|
||||
// Hashes input data using blake2b with 256 bit output.
|
||||
func (ps pricedSyscalls) HashBlake2b(data []byte) [32]byte {
|
||||
ps.chargeGas(ps.pl.OnHashing(len(data)))
|
||||
return ps.under.HashBlake2b(data)
|
||||
}
|
||||
|
||||
// Computes an unsealed sector CID (CommD) from its constituent piece CIDs (CommPs) and sizes.
|
||||
func (ps pricedSyscalls) ComputeUnsealedSectorCID(reg abi.RegisteredProof, pieces []abi.PieceInfo) (cid.Cid, error) {
|
||||
ps.chargeGas(ps.pl.OnComputeUnsealedSectorCid(reg, pieces))
|
||||
return ps.under.ComputeUnsealedSectorCID(reg, pieces)
|
||||
}
|
||||
|
||||
// Verifies a sector seal proof.
|
||||
func (ps pricedSyscalls) VerifySeal(vi abi.SealVerifyInfo) error {
|
||||
ps.chargeGas(ps.pl.OnVerifySeal(vi))
|
||||
return ps.under.VerifySeal(vi)
|
||||
}
|
||||
|
||||
// Verifies a proof of spacetime.
|
||||
func (ps pricedSyscalls) VerifyPoSt(vi abi.PoStVerifyInfo) error {
|
||||
ps.chargeGas(ps.pl.OnVerifyPost(vi))
|
||||
return ps.under.VerifyPoSt(vi)
|
||||
}
|
||||
|
||||
// Verifies that two block headers provide proof of a consensus fault:
|
||||
// - both headers mined by the same actor
|
||||
// - headers are different
|
||||
// - first header is of the same or lower epoch as the second
|
||||
// - at least one of the headers appears in the current chain at or after epoch `earliest`
|
||||
// - the headers provide evidence of a fault (see the spec for the different fault types).
|
||||
// The parameters are all serialized block headers. The third "extra" parameter is consulted only for
|
||||
// the "parent grinding fault", in which case it must be the sibling of h1 (same parent tipset) and one of the
|
||||
// blocks in the parent of h2 (i.e. h2's grandparent).
|
||||
// Returns nil and an error if the headers don't prove a fault.
|
||||
func (ps pricedSyscalls) VerifyConsensusFault(h1 []byte, h2 []byte, extra []byte, earliest abi.ChainEpoch) (*runtime.ConsensusFault, error) {
|
||||
ps.chargeGas(ps.pl.OnVerifyConsensusFault())
|
||||
return ps.under.VerifyConsensusFault(h1, h2, extra, earliest)
|
||||
}
|
165
chain/vm/gas_v0.go
Normal file
165
chain/vm/gas_v0.go
Normal file
@ -0,0 +1,165 @@
|
||||
package vm
|
||||
|
||||
import (
|
||||
"github.com/filecoin-project/lotus/chain/actors/aerrors"
|
||||
"github.com/filecoin-project/specs-actors/actors/abi"
|
||||
"github.com/filecoin-project/specs-actors/actors/builtin"
|
||||
"github.com/filecoin-project/specs-actors/actors/crypto"
|
||||
"github.com/filecoin-project/specs-actors/actors/runtime/exitcode"
|
||||
)
|
||||
|
||||
type pricelistV0 struct {
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
// System operations
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
|
||||
// Gas cost charged to the originator of an on-chain message (regardless of
|
||||
// whether it succeeds or fails in application) is given by:
|
||||
// OnChainMessageBase + len(serialized message)*OnChainMessagePerByte
|
||||
// Together, these account for the cost of message propagation and validation,
|
||||
// up to but excluding any actual processing by the VM.
|
||||
// This is the cost a block producer burns when including an invalid message.
|
||||
onChainMessageBase int64
|
||||
onChainMessagePerByte int64
|
||||
|
||||
// Gas cost charged to the originator of a non-nil return value produced
|
||||
// by an on-chain message is given by:
|
||||
// len(return value)*OnChainReturnValuePerByte
|
||||
onChainReturnValuePerByte int64
|
||||
|
||||
// Gas cost for any message send execution(including the top-level one
|
||||
// initiated by an on-chain message).
|
||||
// This accounts for the cost of loading sender and receiver actors and
|
||||
// (for top-level messages) incrementing the sender's sequence number.
|
||||
// Load and store of actor sub-state is charged separately.
|
||||
sendBase int64
|
||||
|
||||
// Gas cost charged, in addition to SendBase, if a message send
|
||||
// is accompanied by any nonzero currency amount.
|
||||
// Accounts for writing receiver's new balance (the sender's state is
|
||||
// already accounted for).
|
||||
sendTransferFunds int64
|
||||
|
||||
// Gas cost charged, in addition to SendBase, if a message invokes
|
||||
// a method on the receiver.
|
||||
// Accounts for the cost of loading receiver code and method dispatch.
|
||||
sendInvokeMethod int64
|
||||
|
||||
// Gas cost (Base + len*PerByte) for any Get operation to the IPLD store
|
||||
// in the runtime VM context.
|
||||
ipldGetBase int64
|
||||
ipldGetPerByte int64
|
||||
|
||||
// Gas cost (Base + len*PerByte) for any Put operation to the IPLD store
|
||||
// in the runtime VM context.
|
||||
//
|
||||
// Note: these costs should be significantly higher than the costs for Get
|
||||
// operations, since they reflect not only serialization/deserialization
|
||||
// but also persistent storage of chain data.
|
||||
ipldPutBase int64
|
||||
ipldPutPerByte int64
|
||||
|
||||
// Gas cost for creating a new actor (via InitActor's Exec method).
|
||||
//
|
||||
// Note: this costs assume that the extra will be partially or totally refunded while
|
||||
// the base is covering for the put.
|
||||
createActorBase int64
|
||||
createActorExtra int64
|
||||
|
||||
// Gas cost for deleting an actor.
|
||||
//
|
||||
// Note: this partially refunds the create cost to incentivise the deletion of the actors.
|
||||
deleteActor int64
|
||||
|
||||
verifySignature map[crypto.SigType]func(len int64) int64
|
||||
|
||||
hashingBase int64
|
||||
hashingPerByte int64
|
||||
|
||||
computeUnsealedSectorCidBase int64
|
||||
verifySealBase int64
|
||||
verifyPostBase int64
|
||||
verifyConsensusFault int64
|
||||
}
|
||||
|
||||
var _ Pricelist = (*pricelistV0)(nil)
|
||||
|
||||
// OnChainMessage returns the gas used for storing a message of a given size in the chain.
|
||||
func (pl *pricelistV0) OnChainMessage(msgSize int) int64 {
|
||||
return pl.onChainMessageBase + pl.onChainMessagePerByte*int64(msgSize)
|
||||
}
|
||||
|
||||
// OnChainReturnValue returns the gas used for storing the response of a message in the chain.
|
||||
func (pl *pricelistV0) OnChainReturnValue(dataSize int) int64 {
|
||||
return int64(dataSize) * pl.onChainReturnValuePerByte
|
||||
}
|
||||
|
||||
// OnMethodInvocation returns the gas used when invoking a method.
|
||||
func (pl *pricelistV0) OnMethodInvocation(value abi.TokenAmount, methodNum abi.MethodNum) int64 {
|
||||
ret := pl.sendBase
|
||||
if value != abi.NewTokenAmount(0) {
|
||||
ret += pl.sendTransferFunds
|
||||
}
|
||||
if methodNum != builtin.MethodSend {
|
||||
ret += pl.sendInvokeMethod
|
||||
}
|
||||
return ret
|
||||
}
|
||||
|
||||
// OnIpldGet returns the gas used for storing an object
|
||||
func (pl *pricelistV0) OnIpldGet(dataSize int) int64 {
|
||||
return pl.ipldGetBase + int64(dataSize)*pl.ipldGetPerByte
|
||||
}
|
||||
|
||||
// OnIpldPut returns the gas used for storing an object
|
||||
func (pl *pricelistV0) OnIpldPut(dataSize int) int64 {
|
||||
return pl.ipldPutBase + int64(dataSize)*pl.ipldPutPerByte
|
||||
}
|
||||
|
||||
// OnCreateActor returns the gas used for creating an actor
|
||||
func (pl *pricelistV0) OnCreateActor() int64 {
|
||||
return pl.createActorBase + pl.createActorExtra
|
||||
}
|
||||
|
||||
// OnDeleteActor returns the gas used for deleting an actor
|
||||
func (pl *pricelistV0) OnDeleteActor() int64 {
|
||||
return pl.deleteActor
|
||||
}
|
||||
|
||||
// OnVerifySignature
|
||||
func (pl *pricelistV0) OnVerifySignature(sigType crypto.SigType, planTextSize int) int64 {
|
||||
costFn, ok := pl.verifySignature[sigType]
|
||||
if !ok {
|
||||
// TODO: fix retcode to be int64
|
||||
panic(aerrors.Newf(uint8(exitcode.SysErrInternal&0xff), "Cost function for signature type %d not supported", sigType))
|
||||
}
|
||||
return costFn(int64(planTextSize))
|
||||
}
|
||||
|
||||
// OnHashing
|
||||
func (pl *pricelistV0) OnHashing(dataSize int) int64 {
|
||||
return pl.hashingBase + int64(dataSize)*pl.hashingPerByte
|
||||
}
|
||||
|
||||
// OnComputeUnsealedSectorCid
|
||||
func (pl *pricelistV0) OnComputeUnsealedSectorCid(proofType abi.RegisteredProof, pieces []abi.PieceInfo) int64 {
|
||||
// TODO: this needs more cost tunning, check with @lotus
|
||||
return pl.computeUnsealedSectorCidBase
|
||||
}
|
||||
|
||||
// OnVerifySeal
|
||||
func (pl *pricelistV0) OnVerifySeal(info abi.SealVerifyInfo) int64 {
|
||||
// TODO: this needs more cost tunning, check with @lotus
|
||||
return pl.verifySealBase
|
||||
}
|
||||
|
||||
// OnVerifyPost
|
||||
func (pl *pricelistV0) OnVerifyPost(info abi.PoStVerifyInfo) int64 {
|
||||
// TODO: this needs more cost tunning, check with @lotus
|
||||
return pl.verifyPostBase
|
||||
}
|
||||
|
||||
// OnVerifyConsensusFault
|
||||
func (pl *pricelistV0) OnVerifyConsensusFault() int64 {
|
||||
return pl.verifyConsensusFault
|
||||
}
|
@ -4,7 +4,6 @@ import (
|
||||
"bytes"
|
||||
"context"
|
||||
"encoding/binary"
|
||||
"runtime/debug"
|
||||
|
||||
"github.com/filecoin-project/go-address"
|
||||
"github.com/filecoin-project/specs-actors/actors/abi"
|
||||
@ -28,11 +27,12 @@ import (
|
||||
type Runtime struct {
|
||||
ctx context.Context
|
||||
|
||||
vm *VM
|
||||
state *state.StateTree
|
||||
msg *types.Message
|
||||
height abi.ChainEpoch
|
||||
cst cbor.IpldStore
|
||||
vm *VM
|
||||
state *state.StateTree
|
||||
msg *types.Message
|
||||
height abi.ChainEpoch
|
||||
cst cbor.IpldStore
|
||||
pricelist Pricelist
|
||||
|
||||
gasAvailable int64
|
||||
gasUsed int64
|
||||
@ -78,13 +78,11 @@ func (rs *Runtime) shimCall(f func() interface{}) (rval []byte, aerr aerrors.Act
|
||||
defer func() {
|
||||
if r := recover(); r != nil {
|
||||
if ar, ok := r.(aerrors.ActorError); ok {
|
||||
log.Warn("VM.Call failure: ", ar)
|
||||
debug.PrintStack()
|
||||
log.Errorf("VM.Call failure: %+v", ar)
|
||||
aerr = ar
|
||||
return
|
||||
}
|
||||
debug.PrintStack()
|
||||
log.Errorf("ERROR")
|
||||
log.Errorf("spec actors failure: %s", r)
|
||||
aerr = aerrors.Newf(1, "spec actors failure: %s", r)
|
||||
}
|
||||
}()
|
||||
@ -180,6 +178,7 @@ func (rt *Runtime) NewActorAddress() address.Address {
|
||||
}
|
||||
|
||||
func (rt *Runtime) CreateActor(codeId cid.Cid, address address.Address) {
|
||||
rt.ChargeGas(rt.Pricelist().OnCreateActor())
|
||||
var err error
|
||||
|
||||
err = rt.state.SetActor(address, &types.Actor{
|
||||
@ -194,6 +193,7 @@ func (rt *Runtime) CreateActor(codeId cid.Cid, address address.Address) {
|
||||
}
|
||||
|
||||
func (rt *Runtime) DeleteActor() {
|
||||
rt.ChargeGas(rt.Pricelist().OnDeleteActor())
|
||||
act, err := rt.state.GetActor(rt.Message().Receiver())
|
||||
if err != nil {
|
||||
rt.Abortf(exitcode.SysErrInternal, "failed to load actor in delete actor: %s", err)
|
||||
@ -314,6 +314,7 @@ func (rt *Runtime) internalSend(to address.Address, method abi.MethodNum, value
|
||||
return nil, aerrors.Fatalf("snapshot failed: %s", err)
|
||||
}
|
||||
defer st.ClearSnapshot()
|
||||
rt.ChargeGas(rt.Pricelist().OnMethodInvocation(value, method))
|
||||
|
||||
ret, errSend, subrt := rt.vm.send(ctx, msg, rt, 0)
|
||||
if errSend != nil {
|
||||
@ -400,8 +401,6 @@ func (rt *Runtime) GetBalance(a address.Address) (types.BigInt, aerrors.ActorErr
|
||||
}
|
||||
|
||||
func (rt *Runtime) stateCommit(oldh, newh cid.Cid) aerrors.ActorError {
|
||||
rt.ChargeGas(gasCommit)
|
||||
|
||||
// TODO: we can make this more efficient in the future...
|
||||
act, err := rt.state.GetActor(rt.Message().Receiver())
|
||||
if err != nil {
|
||||
@ -422,8 +421,20 @@ func (rt *Runtime) stateCommit(oldh, newh cid.Cid) aerrors.ActorError {
|
||||
}
|
||||
|
||||
func (rt *Runtime) ChargeGas(toUse int64) {
|
||||
rt.gasUsed = rt.gasUsed + toUse
|
||||
if rt.gasUsed > rt.gasAvailable {
|
||||
rt.Abortf(exitcode.SysErrOutOfGas, "not enough gas: used=%d, available=%d", rt.gasUsed, rt.gasAvailable)
|
||||
err := rt.chargeGasSafe(toUse)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
}
|
||||
|
||||
func (rt *Runtime) chargeGasSafe(toUse int64) aerrors.ActorError {
|
||||
rt.gasUsed += toUse
|
||||
if rt.gasUsed > rt.gasAvailable {
|
||||
return aerrors.Newf(uint8(exitcode.SysErrOutOfGas), "not enough gas: used=%d, available=%d", rt.gasUsed, rt.gasAvailable)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (rt *Runtime) Pricelist() Pricelist {
|
||||
return rt.pricelist
|
||||
}
|
||||
|
@ -92,22 +92,22 @@ var _ cbor.IpldBlockstore = (*gasChargingBlocks)(nil)
|
||||
|
||||
type gasChargingBlocks struct {
|
||||
chargeGas func(int64)
|
||||
pricelist Pricelist
|
||||
under cbor.IpldBlockstore
|
||||
}
|
||||
|
||||
func (bs *gasChargingBlocks) Get(c cid.Cid) (block.Block, error) {
|
||||
bs.chargeGas(gasGetObj)
|
||||
blk, err := bs.under.Get(c)
|
||||
if err != nil {
|
||||
return nil, aerrors.Escalate(err, "failed to get block from blockstore")
|
||||
}
|
||||
bs.chargeGas(int64(len(blk.RawData())) * gasGetPerByte)
|
||||
bs.chargeGas(bs.pricelist.OnIpldGet(len(blk.RawData())))
|
||||
|
||||
return blk, nil
|
||||
}
|
||||
|
||||
func (bs *gasChargingBlocks) Put(blk block.Block) error {
|
||||
bs.chargeGas(gasPutObj + int64(len(blk.RawData()))*gasPutPerByte)
|
||||
bs.chargeGas(bs.pricelist.OnIpldPut(len(blk.RawData())))
|
||||
|
||||
if err := bs.under.Put(blk); err != nil {
|
||||
return aerrors.Escalate(err, "failed to write data to disk")
|
||||
@ -124,16 +124,21 @@ func (vm *VM) makeRuntime(ctx context.Context, msg *types.Message, origin addres
|
||||
origin: origin,
|
||||
originNonce: originNonce,
|
||||
height: vm.blockHeight,
|
||||
sys: vm.Syscalls,
|
||||
|
||||
gasUsed: usedGas,
|
||||
gasAvailable: msg.GasLimit,
|
||||
internalCallCounter: icc,
|
||||
pricelist: PricelistByEpoch(vm.blockHeight),
|
||||
}
|
||||
rt.cst = &cbor.BasicIpldStore{
|
||||
Blocks: &gasChargingBlocks{rt.ChargeGas, vm.cst.Blocks},
|
||||
Blocks: &gasChargingBlocks{rt.ChargeGas, rt.pricelist, vm.cst.Blocks},
|
||||
Atlas: vm.cst.Atlas,
|
||||
}
|
||||
rt.sys = pricedSyscalls{
|
||||
under: vm.Syscalls,
|
||||
chargeGas: rt.ChargeGas,
|
||||
pl: rt.pricelist,
|
||||
}
|
||||
|
||||
return rt
|
||||
}
|
||||
@ -193,6 +198,8 @@ func (vm *VM) send(ctx context.Context, msg *types.Message, parent *Runtime,
|
||||
return nil, aerrors.Absorb(err, 1, "could not find source actor"), nil
|
||||
}
|
||||
|
||||
gasUsed := gasCharge
|
||||
|
||||
toActor, err := st.GetActor(msg.To)
|
||||
if err != nil {
|
||||
if xerrors.Is(err, init_.ErrAddressNotFound) {
|
||||
@ -201,12 +208,12 @@ func (vm *VM) send(ctx context.Context, msg *types.Message, parent *Runtime,
|
||||
return nil, aerrors.Absorb(err, 1, "could not create account"), nil
|
||||
}
|
||||
toActor = a
|
||||
gasUsed += PricelistByEpoch(vm.blockHeight).OnCreateActor()
|
||||
} else {
|
||||
return nil, aerrors.Escalate(err, "getting actor"), nil
|
||||
}
|
||||
}
|
||||
|
||||
gasUsed := gasCharge
|
||||
origin := msg.From
|
||||
on := msg.Nonce
|
||||
var icc int64 = 0
|
||||
@ -223,9 +230,12 @@ func (vm *VM) send(ctx context.Context, msg *types.Message, parent *Runtime,
|
||||
}()
|
||||
}
|
||||
|
||||
if types.BigCmp(msg.Value, types.NewInt(0)) != 0 {
|
||||
rt.ChargeGas(gasFundTransfer)
|
||||
aerr := rt.chargeGasSafe(rt.Pricelist().OnMethodInvocation(msg.Value, msg.Method))
|
||||
if aerr != nil {
|
||||
return nil, aerr, rt
|
||||
}
|
||||
|
||||
if types.BigCmp(msg.Value, types.NewInt(0)) != 0 {
|
||||
if err := Transfer(fromActor, toActor, msg.Value); err != nil {
|
||||
return nil, aerrors.Absorb(err, 1, "failed to transfer funds"), nil
|
||||
}
|
||||
@ -273,11 +283,13 @@ func (vm *VM) ApplyMessage(ctx context.Context, msg *types.Message) (*ApplyRet,
|
||||
return nil, err
|
||||
}
|
||||
|
||||
pl := PricelistByEpoch(vm.blockHeight)
|
||||
serMsg, err := msg.Serialize()
|
||||
if err != nil {
|
||||
return nil, xerrors.Errorf("could not serialize message: %w", err)
|
||||
}
|
||||
msgGasCost := int64(len(serMsg)) * gasPerMessageByte
|
||||
msgGasCost := pl.OnChainMessage(len(serMsg))
|
||||
// TODO: charge miner??
|
||||
if msgGasCost > msg.GasLimit {
|
||||
return &ApplyRet{
|
||||
MessageReceipt: types.MessageReceipt{
|
||||
@ -335,6 +347,14 @@ func (vm *VM) ApplyMessage(ctx context.Context, msg *types.Message) (*ApplyRet,
|
||||
|
||||
ret, actorErr, rt := vm.send(ctx, msg, nil, msgGasCost)
|
||||
|
||||
{
|
||||
actorErr2 := rt.chargeGasSafe(rt.Pricelist().OnChainReturnValue(len(ret)))
|
||||
if actorErr == nil {
|
||||
//TODO: Ambigous what to do in this case
|
||||
actorErr = actorErr2
|
||||
}
|
||||
}
|
||||
|
||||
if aerrors.IsFatal(actorErr) {
|
||||
return nil, xerrors.Errorf("[from=%s,to=%s,n=%d,m=%d,h=%d] fatal error: %w", msg.From, msg.To, msg.Nonce, msg.Method, vm.blockHeight, actorErr)
|
||||
}
|
||||
@ -353,6 +373,9 @@ func (vm *VM) ApplyMessage(ctx context.Context, msg *types.Message) (*ApplyRet,
|
||||
}
|
||||
} else {
|
||||
gasUsed = rt.gasUsed
|
||||
if gasUsed < 0 {
|
||||
gasUsed = 0
|
||||
}
|
||||
// refund unused gas
|
||||
refund := types.BigMul(types.NewInt(uint64(msg.GasLimit-gasUsed)), msg.GasPrice)
|
||||
if err := Transfer(gasHolder, fromActor, refund); err != nil {
|
||||
@ -547,7 +570,6 @@ func (vm *VM) Invoke(act *types.Actor, rt *Runtime, method abi.MethodNum, params
|
||||
defer func() {
|
||||
rt.ctx = oldCtx
|
||||
}()
|
||||
rt.ChargeGas(gasInvoke)
|
||||
ret, err := vm.inv.Invoke(act, rt, method, params)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
|
2
go.mod
2
go.mod
@ -11,7 +11,7 @@ require (
|
||||
github.com/StackExchange/wmi v0.0.0-20190523213315-cbe66965904d // indirect
|
||||
github.com/coreos/go-systemd/v22 v22.0.0
|
||||
github.com/docker/go-units v0.4.0
|
||||
github.com/filecoin-project/chain-validation v0.0.6-0.20200318065243-0ccb5ec3afc5
|
||||
github.com/filecoin-project/chain-validation v0.0.6-0.20200320065847-72b36edba0fd
|
||||
github.com/filecoin-project/filecoin-ffi v0.0.0-20200304181354-4446ff8a1bb9
|
||||
github.com/filecoin-project/go-address v0.0.2-0.20200218010043-eb9bb40ed5be
|
||||
github.com/filecoin-project/go-amt-ipld/v2 v2.0.1-0.20200131012142-05d80eeccc5e
|
||||
|
6
go.sum
6
go.sum
@ -98,8 +98,8 @@ github.com/eapache/go-xerial-snappy v0.0.0-20180814174437-776d5712da21/go.mod h1
|
||||
github.com/eapache/queue v1.1.0/go.mod h1:6eCeP0CKFpHLu8blIFXhExK/dRa7WDZfr6jVFPTqq+I=
|
||||
github.com/fatih/color v1.8.0 h1:5bzFgL+oy7JITMTxUPJ00n7VxmYd/PdMp5mHFX40/RY=
|
||||
github.com/fatih/color v1.8.0/go.mod h1:3l45GVGkyrnYNl9HoIjnp2NnNWvh6hLAqD8yTfGjnw8=
|
||||
github.com/filecoin-project/chain-validation v0.0.6-0.20200318065243-0ccb5ec3afc5 h1:cr9+8iX+u9fDV53MWqqZw820EyeWVX+h/HCz56JUWb0=
|
||||
github.com/filecoin-project/chain-validation v0.0.6-0.20200318065243-0ccb5ec3afc5/go.mod h1:7HoEkq8OWN3vGcCZ4SRGxAPeL/mLckS+PNV3F0XmrCs=
|
||||
github.com/filecoin-project/chain-validation v0.0.6-0.20200320065847-72b36edba0fd h1:4sf6dbvA/ZmCcU834shF9hEuHeC+CXoEnT+EIiZ95/0=
|
||||
github.com/filecoin-project/chain-validation v0.0.6-0.20200320065847-72b36edba0fd/go.mod h1:YTLxUr6gOZpkUaXzLe7OZ4s1dpfJGp2FY/J2/K5DJqc=
|
||||
github.com/filecoin-project/go-address v0.0.0-20200107215422-da8eea2842b5 h1:/MmWluswvDIbuPvBct4q6HeQgVm62O2DzWYTB38kt4A=
|
||||
github.com/filecoin-project/go-address v0.0.0-20200107215422-da8eea2842b5/go.mod h1:SAOwJoakQ8EPjwNIsiakIQKsoKdkcbx8U3IapgCg9R0=
|
||||
github.com/filecoin-project/go-address v0.0.2-0.20200218010043-eb9bb40ed5be h1:TooKBwR/g8jG0hZ3lqe9S5sy2vTUcLOZLlz3M5wGn2E=
|
||||
@ -133,8 +133,6 @@ github.com/filecoin-project/specs-actors v0.0.0-20200210130641-2d1fbd8672cf/go.m
|
||||
github.com/filecoin-project/specs-actors v0.0.0-20200226200336-94c9b92b2775/go.mod h1:0HAWYrvajFHDgRaKbF0rl+IybVLZL5z4gQ8koCMPhoU=
|
||||
github.com/filecoin-project/specs-actors v0.0.0-20200302223606-0eaf97b10aaf/go.mod h1:0HAWYrvajFHDgRaKbF0rl+IybVLZL5z4gQ8koCMPhoU=
|
||||
github.com/filecoin-project/specs-actors v0.0.0-20200306000749-99e98e61e2a0/go.mod h1:0HAWYrvajFHDgRaKbF0rl+IybVLZL5z4gQ8koCMPhoU=
|
||||
github.com/filecoin-project/specs-actors v0.0.0-20200311215506-e95895452888 h1:VCrkpFmZuQRyHrUpFTS3K/09cCQDMi/ZJUQ6c4zr1g4=
|
||||
github.com/filecoin-project/specs-actors v0.0.0-20200311215506-e95895452888/go.mod h1:5WngRgTN5Eo4+0SjCBqLzEr2l6Mj45DrP2606gBhqI0=
|
||||
github.com/filecoin-project/specs-actors v0.0.0-20200312030511-3f5510bf6130 h1:atiWEDtI/gzSm89fL+NyneLN3eHfBd1QPgOZyXPjA5M=
|
||||
github.com/filecoin-project/specs-actors v0.0.0-20200312030511-3f5510bf6130/go.mod h1:5WngRgTN5Eo4+0SjCBqLzEr2l6Mj45DrP2606gBhqI0=
|
||||
github.com/filecoin-project/specs-storage v0.0.0-20200303233430-1a5a408f7513 h1:okBx3lPomwDxlPmRvyP078BwivDfdxNUlpCDhDD0ia8=
|
||||
|
Loading…
Reference in New Issue
Block a user