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"
|
"bytes"
|
||||||
"context"
|
"context"
|
||||||
"encoding/binary"
|
"encoding/binary"
|
||||||
"runtime/debug"
|
|
||||||
|
|
||||||
"github.com/filecoin-project/go-address"
|
"github.com/filecoin-project/go-address"
|
||||||
"github.com/filecoin-project/specs-actors/actors/abi"
|
"github.com/filecoin-project/specs-actors/actors/abi"
|
||||||
@ -28,11 +27,12 @@ import (
|
|||||||
type Runtime struct {
|
type Runtime struct {
|
||||||
ctx context.Context
|
ctx context.Context
|
||||||
|
|
||||||
vm *VM
|
vm *VM
|
||||||
state *state.StateTree
|
state *state.StateTree
|
||||||
msg *types.Message
|
msg *types.Message
|
||||||
height abi.ChainEpoch
|
height abi.ChainEpoch
|
||||||
cst cbor.IpldStore
|
cst cbor.IpldStore
|
||||||
|
pricelist Pricelist
|
||||||
|
|
||||||
gasAvailable int64
|
gasAvailable int64
|
||||||
gasUsed int64
|
gasUsed int64
|
||||||
@ -78,13 +78,11 @@ func (rs *Runtime) shimCall(f func() interface{}) (rval []byte, aerr aerrors.Act
|
|||||||
defer func() {
|
defer func() {
|
||||||
if r := recover(); r != nil {
|
if r := recover(); r != nil {
|
||||||
if ar, ok := r.(aerrors.ActorError); ok {
|
if ar, ok := r.(aerrors.ActorError); ok {
|
||||||
log.Warn("VM.Call failure: ", ar)
|
log.Errorf("VM.Call failure: %+v", ar)
|
||||||
debug.PrintStack()
|
|
||||||
aerr = ar
|
aerr = ar
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
debug.PrintStack()
|
log.Errorf("spec actors failure: %s", r)
|
||||||
log.Errorf("ERROR")
|
|
||||||
aerr = aerrors.Newf(1, "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) {
|
func (rt *Runtime) CreateActor(codeId cid.Cid, address address.Address) {
|
||||||
|
rt.ChargeGas(rt.Pricelist().OnCreateActor())
|
||||||
var err error
|
var err error
|
||||||
|
|
||||||
err = rt.state.SetActor(address, &types.Actor{
|
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() {
|
func (rt *Runtime) DeleteActor() {
|
||||||
|
rt.ChargeGas(rt.Pricelist().OnDeleteActor())
|
||||||
act, err := rt.state.GetActor(rt.Message().Receiver())
|
act, err := rt.state.GetActor(rt.Message().Receiver())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
rt.Abortf(exitcode.SysErrInternal, "failed to load actor in delete actor: %s", err)
|
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)
|
return nil, aerrors.Fatalf("snapshot failed: %s", err)
|
||||||
}
|
}
|
||||||
defer st.ClearSnapshot()
|
defer st.ClearSnapshot()
|
||||||
|
rt.ChargeGas(rt.Pricelist().OnMethodInvocation(value, method))
|
||||||
|
|
||||||
ret, errSend, subrt := rt.vm.send(ctx, msg, rt, 0)
|
ret, errSend, subrt := rt.vm.send(ctx, msg, rt, 0)
|
||||||
if errSend != nil {
|
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 {
|
func (rt *Runtime) stateCommit(oldh, newh cid.Cid) aerrors.ActorError {
|
||||||
rt.ChargeGas(gasCommit)
|
|
||||||
|
|
||||||
// TODO: we can make this more efficient in the future...
|
// TODO: we can make this more efficient in the future...
|
||||||
act, err := rt.state.GetActor(rt.Message().Receiver())
|
act, err := rt.state.GetActor(rt.Message().Receiver())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -422,8 +421,20 @@ func (rt *Runtime) stateCommit(oldh, newh cid.Cid) aerrors.ActorError {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (rt *Runtime) ChargeGas(toUse int64) {
|
func (rt *Runtime) ChargeGas(toUse int64) {
|
||||||
rt.gasUsed = rt.gasUsed + toUse
|
err := rt.chargeGasSafe(toUse)
|
||||||
if rt.gasUsed > rt.gasAvailable {
|
if err != nil {
|
||||||
rt.Abortf(exitcode.SysErrOutOfGas, "not enough gas: used=%d, available=%d", rt.gasUsed, rt.gasAvailable)
|
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 {
|
type gasChargingBlocks struct {
|
||||||
chargeGas func(int64)
|
chargeGas func(int64)
|
||||||
|
pricelist Pricelist
|
||||||
under cbor.IpldBlockstore
|
under cbor.IpldBlockstore
|
||||||
}
|
}
|
||||||
|
|
||||||
func (bs *gasChargingBlocks) Get(c cid.Cid) (block.Block, error) {
|
func (bs *gasChargingBlocks) Get(c cid.Cid) (block.Block, error) {
|
||||||
bs.chargeGas(gasGetObj)
|
|
||||||
blk, err := bs.under.Get(c)
|
blk, err := bs.under.Get(c)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, aerrors.Escalate(err, "failed to get block from blockstore")
|
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
|
return blk, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (bs *gasChargingBlocks) Put(blk block.Block) error {
|
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 {
|
if err := bs.under.Put(blk); err != nil {
|
||||||
return aerrors.Escalate(err, "failed to write data to disk")
|
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,
|
origin: origin,
|
||||||
originNonce: originNonce,
|
originNonce: originNonce,
|
||||||
height: vm.blockHeight,
|
height: vm.blockHeight,
|
||||||
sys: vm.Syscalls,
|
|
||||||
|
|
||||||
gasUsed: usedGas,
|
gasUsed: usedGas,
|
||||||
gasAvailable: msg.GasLimit,
|
gasAvailable: msg.GasLimit,
|
||||||
internalCallCounter: icc,
|
internalCallCounter: icc,
|
||||||
|
pricelist: PricelistByEpoch(vm.blockHeight),
|
||||||
}
|
}
|
||||||
rt.cst = &cbor.BasicIpldStore{
|
rt.cst = &cbor.BasicIpldStore{
|
||||||
Blocks: &gasChargingBlocks{rt.ChargeGas, vm.cst.Blocks},
|
Blocks: &gasChargingBlocks{rt.ChargeGas, rt.pricelist, vm.cst.Blocks},
|
||||||
Atlas: vm.cst.Atlas,
|
Atlas: vm.cst.Atlas,
|
||||||
}
|
}
|
||||||
|
rt.sys = pricedSyscalls{
|
||||||
|
under: vm.Syscalls,
|
||||||
|
chargeGas: rt.ChargeGas,
|
||||||
|
pl: rt.pricelist,
|
||||||
|
}
|
||||||
|
|
||||||
return rt
|
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
|
return nil, aerrors.Absorb(err, 1, "could not find source actor"), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
gasUsed := gasCharge
|
||||||
|
|
||||||
toActor, err := st.GetActor(msg.To)
|
toActor, err := st.GetActor(msg.To)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
if xerrors.Is(err, init_.ErrAddressNotFound) {
|
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
|
return nil, aerrors.Absorb(err, 1, "could not create account"), nil
|
||||||
}
|
}
|
||||||
toActor = a
|
toActor = a
|
||||||
|
gasUsed += PricelistByEpoch(vm.blockHeight).OnCreateActor()
|
||||||
} else {
|
} else {
|
||||||
return nil, aerrors.Escalate(err, "getting actor"), nil
|
return nil, aerrors.Escalate(err, "getting actor"), nil
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
gasUsed := gasCharge
|
|
||||||
origin := msg.From
|
origin := msg.From
|
||||||
on := msg.Nonce
|
on := msg.Nonce
|
||||||
var icc int64 = 0
|
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 {
|
aerr := rt.chargeGasSafe(rt.Pricelist().OnMethodInvocation(msg.Value, msg.Method))
|
||||||
rt.ChargeGas(gasFundTransfer)
|
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 {
|
if err := Transfer(fromActor, toActor, msg.Value); err != nil {
|
||||||
return nil, aerrors.Absorb(err, 1, "failed to transfer funds"), 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
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pl := PricelistByEpoch(vm.blockHeight)
|
||||||
serMsg, err := msg.Serialize()
|
serMsg, err := msg.Serialize()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, xerrors.Errorf("could not serialize message: %w", err)
|
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 {
|
if msgGasCost > msg.GasLimit {
|
||||||
return &ApplyRet{
|
return &ApplyRet{
|
||||||
MessageReceipt: types.MessageReceipt{
|
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)
|
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) {
|
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)
|
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 {
|
} else {
|
||||||
gasUsed = rt.gasUsed
|
gasUsed = rt.gasUsed
|
||||||
|
if gasUsed < 0 {
|
||||||
|
gasUsed = 0
|
||||||
|
}
|
||||||
// refund unused gas
|
// refund unused gas
|
||||||
refund := types.BigMul(types.NewInt(uint64(msg.GasLimit-gasUsed)), msg.GasPrice)
|
refund := types.BigMul(types.NewInt(uint64(msg.GasLimit-gasUsed)), msg.GasPrice)
|
||||||
if err := Transfer(gasHolder, fromActor, refund); err != nil {
|
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() {
|
defer func() {
|
||||||
rt.ctx = oldCtx
|
rt.ctx = oldCtx
|
||||||
}()
|
}()
|
||||||
rt.ChargeGas(gasInvoke)
|
|
||||||
ret, err := vm.inv.Invoke(act, rt, method, params)
|
ret, err := vm.inv.Invoke(act, rt, method, params)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
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/StackExchange/wmi v0.0.0-20190523213315-cbe66965904d // indirect
|
||||||
github.com/coreos/go-systemd/v22 v22.0.0
|
github.com/coreos/go-systemd/v22 v22.0.0
|
||||||
github.com/docker/go-units v0.4.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/filecoin-ffi v0.0.0-20200304181354-4446ff8a1bb9
|
||||||
github.com/filecoin-project/go-address v0.0.2-0.20200218010043-eb9bb40ed5be
|
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
|
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/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 h1:5bzFgL+oy7JITMTxUPJ00n7VxmYd/PdMp5mHFX40/RY=
|
||||||
github.com/fatih/color v1.8.0/go.mod h1:3l45GVGkyrnYNl9HoIjnp2NnNWvh6hLAqD8yTfGjnw8=
|
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.20200320065847-72b36edba0fd h1:4sf6dbvA/ZmCcU834shF9hEuHeC+CXoEnT+EIiZ95/0=
|
||||||
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/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 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.0-20200107215422-da8eea2842b5/go.mod h1:SAOwJoakQ8EPjwNIsiakIQKsoKdkcbx8U3IapgCg9R0=
|
||||||
github.com/filecoin-project/go-address v0.0.2-0.20200218010043-eb9bb40ed5be h1:TooKBwR/g8jG0hZ3lqe9S5sy2vTUcLOZLlz3M5wGn2E=
|
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-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-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-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 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-actors v0.0.0-20200312030511-3f5510bf6130/go.mod h1:5WngRgTN5Eo4+0SjCBqLzEr2l6Mj45DrP2606gBhqI0=
|
||||||
github.com/filecoin-project/specs-storage v0.0.0-20200303233430-1a5a408f7513 h1:okBx3lPomwDxlPmRvyP078BwivDfdxNUlpCDhDD0ia8=
|
github.com/filecoin-project/specs-storage v0.0.0-20200303233430-1a5a408f7513 h1:okBx3lPomwDxlPmRvyP078BwivDfdxNUlpCDhDD0ia8=
|
||||||
|
Loading…
Reference in New Issue
Block a user