lotus/chain/vm/gas.go

231 lines
7.1 KiB
Go
Raw Permalink Normal View History

2020-03-19 16:27:42 +00:00
package vm
import (
"fmt"
"github.com/filecoin-project/go-address"
2020-03-19 16:27:42 +00:00
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"
)
const (
GasStorageMulti = 1000
GasComputeMulti = 1
)
type GasCharge struct {
Name string
Extra interface{}
ComputeGas int64
StorageGas int64
VirtualCompute int64
VirtualStorage int64
}
func (g GasCharge) Total() int64 {
return g.ComputeGas*GasComputeMulti + g.StorageGas*GasStorageMulti
}
func (g GasCharge) WithVirtual(compute, storage int64) GasCharge {
out := g
out.VirtualCompute = compute
out.VirtualStorage = storage
return out
}
func (g GasCharge) WithExtra(extra interface{}) GasCharge {
out := g
out.Extra = extra
return out
}
func newGasCharge(name string, computeGas int64, storageGas int64) GasCharge {
return GasCharge{
Name: name,
ComputeGas: computeGas,
StorageGas: storageGas,
}
}
2020-03-19 16:27:42 +00:00
// 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) GasCharge
2020-03-19 16:27:42 +00:00
// OnChainReturnValue returns the gas used for storing the response of a message in the chain.
OnChainReturnValue(dataSize int) GasCharge
2020-03-19 16:27:42 +00:00
// OnMethodInvocation returns the gas used when invoking a method.
OnMethodInvocation(value abi.TokenAmount, methodNum abi.MethodNum) GasCharge
2020-03-19 16:27:42 +00:00
// OnIpldGet returns the gas used for storing an object
OnIpldGet() GasCharge
2020-03-19 16:27:42 +00:00
// OnIpldPut returns the gas used for storing an object
OnIpldPut(dataSize int) GasCharge
2020-03-19 16:27:42 +00:00
// OnCreateActor returns the gas used for creating an actor
OnCreateActor() GasCharge
2020-03-19 16:27:42 +00:00
// OnDeleteActor returns the gas used for deleting an actor
OnDeleteActor() GasCharge
OnVerifySignature(sigType crypto.SigType, planTextSize int) (GasCharge, error)
OnHashing(dataSize int) GasCharge
2020-06-15 16:30:49 +00:00
OnComputeUnsealedSectorCid(proofType abi.RegisteredSealProof, pieces []abi.PieceInfo) GasCharge
OnVerifySeal(info abi.SealVerifyInfo) GasCharge
OnVerifyPost(info abi.WindowPoStVerifyInfo) GasCharge
OnVerifyConsensusFault() GasCharge
2020-03-19 16:27:42 +00:00
}
var prices = map[abi.ChainEpoch]Pricelist{
abi.ChainEpoch(0): &pricelistV0{
onChainMessageComputeBase: 38863,
onChainMessageStorageBase: 36,
onChainMessageStoragePerByte: 1,
onChainReturnValuePerByte: 1,
sendBase: 29233,
sendTransferFunds: 27500,
sendTransferOnlyPremium: 159672,
sendInvokeMethod: -5377,
ipldGetBase: 75242,
ipldPutBase: 84070,
ipldPutPerByte: 1,
createActorCompute: 1108454,
createActorStorage: 36 + 40,
deleteActor: -(36 + 40), // -createActorStorage
verifySignature: map[crypto.SigType]int64{
crypto.SigTypeBLS: 16598605,
crypto.SigTypeSecp256k1: 1637292,
2020-03-19 16:27:42 +00:00
},
hashingBase: 31355,
computeUnsealedSectorCidBase: 98647,
verifySealBase: 2000, // TODO gas , it VerifySeal syscall is not used
verifyPostLookup: map[abi.RegisteredPoStProof]scalingCost{
abi.RegisteredPoStProof_StackedDrgWindow512MiBV1: {
flat: 123861062,
scale: 9226981,
},
abi.RegisteredPoStProof_StackedDrgWindow32GiBV1: {
flat: 748593537,
scale: 85639,
},
abi.RegisteredPoStProof_StackedDrgWindow64GiBV1: {
flat: 748593537,
scale: 85639,
},
},
verifyConsensusFault: 495422,
2020-03-19 16:27:42 +00:00
},
}
// 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(GasCharge)
2020-03-19 16:27:42 +00:00
}
// Verifies that a signature is valid for an address and plaintext.
func (ps pricedSyscalls) VerifySignature(signature crypto.Signature, signer addr.Address, plaintext []byte) error {
c, err := ps.pl.OnVerifySignature(signature.Type, len(plaintext))
if err != nil {
return err
}
ps.chargeGas(c)
defer ps.chargeGas(gasOnActorExec)
2020-03-19 16:27:42 +00:00
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)))
defer ps.chargeGas(gasOnActorExec)
2020-03-19 16:27:42 +00:00
return ps.under.HashBlake2b(data)
}
// Computes an unsealed sector CID (CommD) from its constituent piece CIDs (CommPs) and sizes.
2020-06-15 16:30:49 +00:00
func (ps pricedSyscalls) ComputeUnsealedSectorCID(reg abi.RegisteredSealProof, pieces []abi.PieceInfo) (cid.Cid, error) {
2020-03-19 16:27:42 +00:00
ps.chargeGas(ps.pl.OnComputeUnsealedSectorCid(reg, pieces))
defer ps.chargeGas(gasOnActorExec)
2020-03-19 16:27:42 +00:00
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))
defer ps.chargeGas(gasOnActorExec)
2020-03-19 16:27:42 +00:00
return ps.under.VerifySeal(vi)
}
// Verifies a proof of spacetime.
2020-04-10 12:19:06 +00:00
func (ps pricedSyscalls) VerifyPoSt(vi abi.WindowPoStVerifyInfo) error {
2020-03-19 16:27:42 +00:00
ps.chargeGas(ps.pl.OnVerifyPost(vi))
defer ps.chargeGas(gasOnActorExec)
2020-03-19 16:27:42 +00:00
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.
2020-04-16 16:41:45 +00:00
func (ps pricedSyscalls) VerifyConsensusFault(h1 []byte, h2 []byte, extra []byte) (*runtime.ConsensusFault, error) {
2020-03-19 16:27:42 +00:00
ps.chargeGas(ps.pl.OnVerifyConsensusFault())
defer ps.chargeGas(gasOnActorExec)
2020-04-16 16:41:45 +00:00
return ps.under.VerifyConsensusFault(h1, h2, extra)
2020-03-19 16:27:42 +00:00
}
func (ps pricedSyscalls) BatchVerifySeals(inp map[address.Address][]abi.SealVerifyInfo) (map[address.Address][]bool, error) {
count := int64(0)
for _, svis := range inp {
count += int64(len(svis))
}
gasChargeSum := newGasCharge("BatchVerifySeals", 0, 0)
gasChargeSum = gasChargeSum.WithExtra(count).WithVirtual(15075005*count+899741502, 0)
ps.chargeGas(gasChargeSum) // real gas charged by actors
defer ps.chargeGas(gasOnActorExec)
return ps.under.BatchVerifySeals(inp)
}