Split gas internally into compute gas and storage gas
Signed-off-by: Jakub Sztandera <kubuxu@protocol.ai>
This commit is contained in:
parent
c8046f4597
commit
6acc9a62f8
@ -12,34 +12,57 @@ import (
|
|||||||
"github.com/ipfs/go-cid"
|
"github.com/ipfs/go-cid"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
GasStorageMulti = 1
|
||||||
|
GasComputeMulti = 1
|
||||||
|
)
|
||||||
|
|
||||||
|
type GasCharge struct {
|
||||||
|
Name string
|
||||||
|
ComputeGas int64
|
||||||
|
StorageGas int64
|
||||||
|
}
|
||||||
|
|
||||||
|
func (g GasCharge) Total() int64 {
|
||||||
|
return g.ComputeGas*GasComputeMulti + g.StorageGas*GasStorageMulti
|
||||||
|
}
|
||||||
|
|
||||||
|
func newGasCharge(name string, computeGas int64, storageGas int64) GasCharge {
|
||||||
|
return GasCharge{
|
||||||
|
Name: name,
|
||||||
|
ComputeGas: computeGas,
|
||||||
|
StorageGas: storageGas,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Pricelist provides prices for operations in the VM.
|
// Pricelist provides prices for operations in the VM.
|
||||||
//
|
//
|
||||||
// Note: this interface should be APPEND ONLY since last chain checkpoint
|
// Note: this interface should be APPEND ONLY since last chain checkpoint
|
||||||
type Pricelist interface {
|
type Pricelist interface {
|
||||||
// OnChainMessage returns the gas used for storing a message of a given size in the chain.
|
// OnChainMessage returns the gas used for storing a message of a given size in the chain.
|
||||||
OnChainMessage(msgSize int) int64
|
OnChainMessage(msgSize int) GasCharge
|
||||||
// OnChainReturnValue returns the gas used for storing the response of a message in the chain.
|
// OnChainReturnValue returns the gas used for storing the response of a message in the chain.
|
||||||
OnChainReturnValue(dataSize int) int64
|
OnChainReturnValue(dataSize int) GasCharge
|
||||||
|
|
||||||
// OnMethodInvocation returns the gas used when invoking a method.
|
// OnMethodInvocation returns the gas used when invoking a method.
|
||||||
OnMethodInvocation(value abi.TokenAmount, methodNum abi.MethodNum) int64
|
OnMethodInvocation(value abi.TokenAmount, methodNum abi.MethodNum) GasCharge
|
||||||
|
|
||||||
// OnIpldGet returns the gas used for storing an object
|
// OnIpldGet returns the gas used for storing an object
|
||||||
OnIpldGet(dataSize int) int64
|
OnIpldGet(dataSize int) GasCharge
|
||||||
// OnIpldPut returns the gas used for storing an object
|
// OnIpldPut returns the gas used for storing an object
|
||||||
OnIpldPut(dataSize int) int64
|
OnIpldPut(dataSize int) GasCharge
|
||||||
|
|
||||||
// OnCreateActor returns the gas used for creating an actor
|
// OnCreateActor returns the gas used for creating an actor
|
||||||
OnCreateActor() int64
|
OnCreateActor() GasCharge
|
||||||
// OnDeleteActor returns the gas used for deleting an actor
|
// OnDeleteActor returns the gas used for deleting an actor
|
||||||
OnDeleteActor() int64
|
OnDeleteActor() GasCharge
|
||||||
|
|
||||||
OnVerifySignature(sigType crypto.SigType, planTextSize int) (int64, error)
|
OnVerifySignature(sigType crypto.SigType, planTextSize int) (GasCharge, error)
|
||||||
OnHashing(dataSize int) int64
|
OnHashing(dataSize int) GasCharge
|
||||||
OnComputeUnsealedSectorCid(proofType abi.RegisteredProof, pieces []abi.PieceInfo) int64
|
OnComputeUnsealedSectorCid(proofType abi.RegisteredProof, pieces []abi.PieceInfo) GasCharge
|
||||||
OnVerifySeal(info abi.SealVerifyInfo) int64
|
OnVerifySeal(info abi.SealVerifyInfo) GasCharge
|
||||||
OnVerifyPost(info abi.WindowPoStVerifyInfo) int64
|
OnVerifyPost(info abi.WindowPoStVerifyInfo) GasCharge
|
||||||
OnVerifyConsensusFault() int64
|
OnVerifyConsensusFault() GasCharge
|
||||||
}
|
}
|
||||||
|
|
||||||
var prices = map[abi.ChainEpoch]Pricelist{
|
var prices = map[abi.ChainEpoch]Pricelist{
|
||||||
@ -93,7 +116,7 @@ func PricelistByEpoch(epoch abi.ChainEpoch) Pricelist {
|
|||||||
type pricedSyscalls struct {
|
type pricedSyscalls struct {
|
||||||
under vmr.Syscalls
|
under vmr.Syscalls
|
||||||
pl Pricelist
|
pl Pricelist
|
||||||
chargeGas func(int64)
|
chargeGas func(GasCharge)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Verifies that a signature is valid for an address and plaintext.
|
// Verifies that a signature is valid for an address and plaintext.
|
||||||
@ -146,6 +169,6 @@ func (ps pricedSyscalls) VerifyConsensusFault(h1 []byte, h2 []byte, extra []byte
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (ps pricedSyscalls) BatchVerifySeals(inp map[address.Address][]abi.SealVerifyInfo) (map[address.Address][]bool, error) {
|
func (ps pricedSyscalls) BatchVerifySeals(inp map[address.Address][]abi.SealVerifyInfo) (map[address.Address][]bool, error) {
|
||||||
ps.chargeGas(0) // TODO: this is only called by the cron actor. Should we even charge gas?
|
ps.chargeGas(newGasCharge("BatchVerifySeals", 0, 0)) // TODO: this is only called by the cron actor. Should we even charge gas?
|
||||||
return ps.under.BatchVerifySeals(inp)
|
return ps.under.BatchVerifySeals(inp)
|
||||||
}
|
}
|
||||||
|
@ -2,6 +2,7 @@ package vm
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
|
|
||||||
"github.com/filecoin-project/specs-actors/actors/abi"
|
"github.com/filecoin-project/specs-actors/actors/abi"
|
||||||
"github.com/filecoin-project/specs-actors/actors/builtin"
|
"github.com/filecoin-project/specs-actors/actors/builtin"
|
||||||
"github.com/filecoin-project/specs-actors/actors/crypto"
|
"github.com/filecoin-project/specs-actors/actors/crypto"
|
||||||
@ -84,17 +85,17 @@ type pricelistV0 struct {
|
|||||||
var _ Pricelist = (*pricelistV0)(nil)
|
var _ Pricelist = (*pricelistV0)(nil)
|
||||||
|
|
||||||
// OnChainMessage returns the gas used for storing a message of a given size in the chain.
|
// OnChainMessage returns the gas used for storing a message of a given size in the chain.
|
||||||
func (pl *pricelistV0) OnChainMessage(msgSize int) int64 {
|
func (pl *pricelistV0) OnChainMessage(msgSize int) GasCharge {
|
||||||
return pl.onChainMessageBase + pl.onChainMessagePerByte*int64(msgSize)
|
return newGasCharge("OnChainMessage", 0, pl.onChainMessageBase+pl.onChainMessagePerByte*int64(msgSize))
|
||||||
}
|
}
|
||||||
|
|
||||||
// OnChainReturnValue returns the gas used for storing the response of a message in the chain.
|
// OnChainReturnValue returns the gas used for storing the response of a message in the chain.
|
||||||
func (pl *pricelistV0) OnChainReturnValue(dataSize int) int64 {
|
func (pl *pricelistV0) OnChainReturnValue(dataSize int) GasCharge {
|
||||||
return int64(dataSize) * pl.onChainReturnValuePerByte
|
return newGasCharge("OnChainReturnValue", 0, int64(dataSize)*pl.onChainReturnValuePerByte)
|
||||||
}
|
}
|
||||||
|
|
||||||
// OnMethodInvocation returns the gas used when invoking a method.
|
// OnMethodInvocation returns the gas used when invoking a method.
|
||||||
func (pl *pricelistV0) OnMethodInvocation(value abi.TokenAmount, methodNum abi.MethodNum) int64 {
|
func (pl *pricelistV0) OnMethodInvocation(value abi.TokenAmount, methodNum abi.MethodNum) GasCharge {
|
||||||
ret := pl.sendBase
|
ret := pl.sendBase
|
||||||
if value != abi.NewTokenAmount(0) {
|
if value != abi.NewTokenAmount(0) {
|
||||||
ret += pl.sendTransferFunds
|
ret += pl.sendTransferFunds
|
||||||
@ -102,62 +103,63 @@ func (pl *pricelistV0) OnMethodInvocation(value abi.TokenAmount, methodNum abi.M
|
|||||||
if methodNum != builtin.MethodSend {
|
if methodNum != builtin.MethodSend {
|
||||||
ret += pl.sendInvokeMethod
|
ret += pl.sendInvokeMethod
|
||||||
}
|
}
|
||||||
return ret
|
return newGasCharge("OnMethodInvocation", ret, 0)
|
||||||
}
|
}
|
||||||
|
|
||||||
// OnIpldGet returns the gas used for storing an object
|
// OnIpldGet returns the gas used for storing an object
|
||||||
func (pl *pricelistV0) OnIpldGet(dataSize int) int64 {
|
func (pl *pricelistV0) OnIpldGet(dataSize int) GasCharge {
|
||||||
return pl.ipldGetBase + int64(dataSize)*pl.ipldGetPerByte
|
return newGasCharge("OnIpldGet", pl.ipldGetBase+int64(dataSize)*pl.ipldGetPerByte, 0)
|
||||||
}
|
}
|
||||||
|
|
||||||
// OnIpldPut returns the gas used for storing an object
|
// OnIpldPut returns the gas used for storing an object
|
||||||
func (pl *pricelistV0) OnIpldPut(dataSize int) int64 {
|
func (pl *pricelistV0) OnIpldPut(dataSize int) GasCharge {
|
||||||
return pl.ipldPutBase + int64(dataSize)*pl.ipldPutPerByte
|
return newGasCharge("OnIpldPut", pl.ipldPutBase, int64(dataSize)*pl.ipldPutPerByte)
|
||||||
}
|
}
|
||||||
|
|
||||||
// OnCreateActor returns the gas used for creating an actor
|
// OnCreateActor returns the gas used for creating an actor
|
||||||
func (pl *pricelistV0) OnCreateActor() int64 {
|
func (pl *pricelistV0) OnCreateActor() GasCharge {
|
||||||
return pl.createActorBase + pl.createActorExtra
|
return newGasCharge("OnCreateActor", pl.createActorBase, pl.createActorExtra)
|
||||||
}
|
}
|
||||||
|
|
||||||
// OnDeleteActor returns the gas used for deleting an actor
|
// OnDeleteActor returns the gas used for deleting an actor
|
||||||
func (pl *pricelistV0) OnDeleteActor() int64 {
|
func (pl *pricelistV0) OnDeleteActor() GasCharge {
|
||||||
return pl.deleteActor
|
return newGasCharge("OnDeleteActor", 0, pl.deleteActor)
|
||||||
}
|
}
|
||||||
|
|
||||||
// OnVerifySignature
|
// OnVerifySignature
|
||||||
func (pl *pricelistV0) OnVerifySignature(sigType crypto.SigType, planTextSize int) (int64, error) {
|
func (pl *pricelistV0) OnVerifySignature(sigType crypto.SigType, planTextSize int) (GasCharge, error) {
|
||||||
costFn, ok := pl.verifySignature[sigType]
|
costFn, ok := pl.verifySignature[sigType]
|
||||||
if !ok {
|
if !ok {
|
||||||
return 0, fmt.Errorf("cost function for signature type %d not supported", sigType)
|
return GasCharge{}, fmt.Errorf("cost function for signature type %d not supported", sigType)
|
||||||
}
|
}
|
||||||
return costFn(int64(planTextSize)), nil
|
sigName, _ := sigType.Name()
|
||||||
|
return newGasCharge("OnVerifySignature/"+sigName, costFn(int64(planTextSize)), 0), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// OnHashing
|
// OnHashing
|
||||||
func (pl *pricelistV0) OnHashing(dataSize int) int64 {
|
func (pl *pricelistV0) OnHashing(dataSize int) GasCharge {
|
||||||
return pl.hashingBase + int64(dataSize)*pl.hashingPerByte
|
return newGasCharge("OnHashing", pl.hashingBase+int64(dataSize)*pl.hashingPerByte, 0)
|
||||||
}
|
}
|
||||||
|
|
||||||
// OnComputeUnsealedSectorCid
|
// OnComputeUnsealedSectorCid
|
||||||
func (pl *pricelistV0) OnComputeUnsealedSectorCid(proofType abi.RegisteredProof, pieces []abi.PieceInfo) int64 {
|
func (pl *pricelistV0) OnComputeUnsealedSectorCid(proofType abi.RegisteredProof, pieces []abi.PieceInfo) GasCharge {
|
||||||
// TODO: this needs more cost tunning, check with @lotus
|
// TODO: this needs more cost tunning, check with @lotus
|
||||||
return pl.computeUnsealedSectorCidBase
|
return newGasCharge("OnComputeUnsealedSectorCid", pl.computeUnsealedSectorCidBase, 0)
|
||||||
}
|
}
|
||||||
|
|
||||||
// OnVerifySeal
|
// OnVerifySeal
|
||||||
func (pl *pricelistV0) OnVerifySeal(info abi.SealVerifyInfo) int64 {
|
func (pl *pricelistV0) OnVerifySeal(info abi.SealVerifyInfo) GasCharge {
|
||||||
// TODO: this needs more cost tunning, check with @lotus
|
// TODO: this needs more cost tunning, check with @lotus
|
||||||
return pl.verifySealBase
|
return newGasCharge("OnVerifySeal", pl.verifySealBase, 0)
|
||||||
}
|
}
|
||||||
|
|
||||||
// OnVerifyPost
|
// OnVerifyPost
|
||||||
func (pl *pricelistV0) OnVerifyPost(info abi.WindowPoStVerifyInfo) int64 {
|
func (pl *pricelistV0) OnVerifyPost(info abi.WindowPoStVerifyInfo) GasCharge {
|
||||||
// TODO: this needs more cost tunning, check with @lotus
|
// TODO: this needs more cost tunning, check with @lotus
|
||||||
return pl.verifyPostBase
|
return newGasCharge("OnVerifyPost", pl.verifyPostBase, 0)
|
||||||
}
|
}
|
||||||
|
|
||||||
// OnVerifyConsensusFault
|
// OnVerifyConsensusFault
|
||||||
func (pl *pricelistV0) OnVerifyConsensusFault() int64 {
|
func (pl *pricelistV0) OnVerifyConsensusFault() GasCharge {
|
||||||
return pl.verifyConsensusFault
|
return newGasCharge("OnVerifyConsensusFault", pl.verifyConsensusFault, 0)
|
||||||
}
|
}
|
||||||
|
@ -484,14 +484,15 @@ func (rt *Runtime) stateCommit(oldh, newh cid.Cid) aerrors.ActorError {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (rt *Runtime) ChargeGas(toUse int64) {
|
func (rt *Runtime) ChargeGas(gas GasCharge) {
|
||||||
err := rt.chargeGasInternal(toUse)
|
err := rt.chargeGasInternal(gas)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
panic(err)
|
panic(err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (rt *Runtime) chargeGasInternal(toUse int64) aerrors.ActorError {
|
func (rt *Runtime) chargeGasInternal(gas GasCharge) aerrors.ActorError {
|
||||||
|
toUse := gas.Total()
|
||||||
if rt.gasUsed+toUse > rt.gasAvailable {
|
if rt.gasUsed+toUse > rt.gasAvailable {
|
||||||
rt.gasUsed = rt.gasAvailable
|
rt.gasUsed = rt.gasAvailable
|
||||||
return aerrors.Newf(exitcode.SysErrOutOfGas, "not enough gas: used=%d, available=%d", rt.gasUsed, rt.gasAvailable)
|
return aerrors.Newf(exitcode.SysErrOutOfGas, "not enough gas: used=%d, available=%d", rt.gasUsed, rt.gasAvailable)
|
||||||
@ -500,8 +501,8 @@ func (rt *Runtime) chargeGasInternal(toUse int64) aerrors.ActorError {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (rt *Runtime) chargeGasSafe(toUse int64) aerrors.ActorError {
|
func (rt *Runtime) chargeGasSafe(gas GasCharge) aerrors.ActorError {
|
||||||
return rt.chargeGasInternal(toUse)
|
return rt.chargeGasInternal(gas)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (rt *Runtime) Pricelist() Pricelist {
|
func (rt *Runtime) Pricelist() Pricelist {
|
||||||
|
@ -62,7 +62,7 @@ func ResolveToKeyAddr(state types.StateTree, cst cbor.IpldStore, addr address.Ad
|
|||||||
var _ cbor.IpldBlockstore = (*gasChargingBlocks)(nil)
|
var _ cbor.IpldBlockstore = (*gasChargingBlocks)(nil)
|
||||||
|
|
||||||
type gasChargingBlocks struct {
|
type gasChargingBlocks struct {
|
||||||
chargeGas func(int64)
|
chargeGas func(GasCharge)
|
||||||
pricelist Pricelist
|
pricelist Pricelist
|
||||||
under cbor.IpldBlockstore
|
under cbor.IpldBlockstore
|
||||||
}
|
}
|
||||||
@ -294,7 +294,7 @@ func (vm *VM) ApplyMessage(ctx context.Context, cmsg types.ChainMsg) (*ApplyRet,
|
|||||||
|
|
||||||
pl := PricelistByEpoch(vm.blockHeight)
|
pl := PricelistByEpoch(vm.blockHeight)
|
||||||
|
|
||||||
msgGasCost := pl.OnChainMessage(cmsg.ChainLength())
|
msgGasCost := pl.OnChainMessage(cmsg.ChainLength()).Total()
|
||||||
// this should never happen, but is currently still exercised by some tests
|
// this should never happen, but is currently still exercised by some tests
|
||||||
if msgGasCost > msg.GasLimit {
|
if msgGasCost > msg.GasLimit {
|
||||||
return &ApplyRet{
|
return &ApplyRet{
|
||||||
|
Loading…
Reference in New Issue
Block a user