Skip to content

Commit

Permalink
Merge pull request #142 from filecoin-project/feat/gas
Browse files Browse the repository at this point in the history
Initial gas charning
  • Loading branch information
Jakub Sztandera authored Aug 16, 2019
2 parents 7402c54 + f6387da commit 5d7c20c
Show file tree
Hide file tree
Showing 7 changed files with 83 additions and 181 deletions.
19 changes: 10 additions & 9 deletions chain/actors/actor_multisig_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ func TestMultiSigCreate(t *testing.T) {
HarnessAddr(&creatorAddr, 10000),
HarnessAddr(&sig1Addr, 10000),
HarnessAddr(&sig2Addr, 10000),
HarnessAddr(&outsideAddr, 10000),
HarnessAddr(&outsideAddr, 1000),
}

h := NewHarness2(t, opts...)
Expand Down Expand Up @@ -53,9 +53,9 @@ func TestMultiSigOps(t *testing.T) {
var multSigAddr address.Address
opts := []HarnessOpt{
HarnessCtx(ctx),
HarnessAddr(&creatorAddr, 10000),
HarnessAddr(&sig1Addr, 10000),
HarnessAddr(&sig2Addr, 10000),
HarnessAddr(&creatorAddr, 100000),
HarnessAddr(&sig1Addr, 100000),
HarnessAddr(&sig2Addr, 100000),
HarnessAddr(&outsideAddr, 1000),
HarnessActor(&multSigAddr, &creatorAddr, actors.MultisigActorCodeCid,
func() interface{} {
Expand All @@ -79,8 +79,9 @@ func TestMultiSigOps(t *testing.T) {

{
// Transfer funds outside of multsig
sendVal := types.NewInt(100)
sendVal := types.NewInt(1000)
ret, _ := h.Invoke(t, creatorAddr, multSigAddr, actors.MultiSigMethods.Propose,

actors.MultiSigProposeParams{
To: outsideAddr,
Value: sendVal,
Expand All @@ -94,14 +95,14 @@ func TestMultiSigOps(t *testing.T) {
txIDParam)
assert.Equal(t, uint8(1), ret.ExitCode, "outsideAddr should not approve")

ret, state := h.Invoke(t, sig1Addr, multSigAddr, actors.MultiSigMethods.Approve,
ret2, state := h.Invoke(t, sig1Addr, multSigAddr, actors.MultiSigMethods.Approve,
txIDParam)
outAct, err := state.GetActor(outsideAddr)
ApplyOK(t, ret)
ApplyOK(t, ret2)
curVal = types.BigSub(curVal, sendVal)

outAct, err := state.GetActor(outsideAddr)
assert.NoError(t, err)
assert.Equal(t, types.NewInt(1099), outAct.Balance)
assert.Equal(t, types.NewInt(uint64(1000+1000-ret.GasUsed.Int64())), outAct.Balance)

msAct, err := state.GetActor(multSigAddr)
assert.NoError(t, err)
Expand Down
4 changes: 2 additions & 2 deletions chain/actors/actor_paych_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -87,6 +87,6 @@ func TestPaychUpdate(t *testing.T) {
ret, _ = h.Invoke(t, targetAddr, pch, actors.PCAMethods.Collect, struct{}{})
ApplyOK(t, ret)

h.AssertBalance(t, targetAddr, 10100)
h.AssertBalance(t, creatorAddr, 9900)
h.AssertBalance(t, targetAddr, 10100-2*10 /*gas cost*/)
h.AssertBalance(t, creatorAddr, 9900-10)
}
12 changes: 7 additions & 5 deletions chain/actors/harness2_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,8 @@ import (
"github.com/filecoin-project/go-lotus/chain/wallet"
)

const testGasLimit = 100

type HarnessInit struct {
NAddrs uint64
Addrs map[address.Address]types.BigInt
Expand Down Expand Up @@ -202,7 +204,7 @@ func (h *Harness2) CreateActor(t testing.TB, from address.Address,
Params: DumpObject(t, params),
}),
GasPrice: types.NewInt(1),
GasLimit: types.NewInt(1),
GasLimit: types.NewInt(testGasLimit),
Value: types.NewInt(0),
})
}
Expand All @@ -216,7 +218,7 @@ func (h *Harness2) SendFunds(t testing.TB, from address.Address, to address.Addr
Method: 0,
Value: value,
GasPrice: types.NewInt(1),
GasLimit: types.NewInt(1),
GasLimit: types.NewInt(testGasLimit),
})
}

Expand All @@ -230,7 +232,7 @@ func (h *Harness2) Invoke(t testing.TB, from address.Address, to address.Address
Value: types.NewInt(0),
Params: DumpObject(t, params),
GasPrice: types.NewInt(1),
GasLimit: types.NewInt(1),
GasLimit: types.NewInt(testGasLimit),
})
}

Expand All @@ -239,11 +241,11 @@ func (h *Harness2) AssertBalance(t testing.TB, addr address.Address, amt uint64)

b, err := h.vm.ActorBalance(addr)
if err != nil {
t.Fatal(err)
t.Fatalf("%+v", err)
}

if types.BigCmp(types.NewInt(amt), b) != 0 {
t.Fatalf("expected %s to have balanced of %d. Instead has %s", addr, amt, b)
t.Errorf("expected %s to have balanced of %d. Instead has %s", addr, amt, b)
}
}

Expand Down
1 change: 1 addition & 0 deletions chain/types/vmcontext.go
Original file line number Diff line number Diff line change
Expand Up @@ -33,4 +33,5 @@ type VMContext interface {
Storage() Storage
StateTree() (StateTree, aerrors.ActorError)
VerifySignature(sig *Signature, from address.Address, data []byte) aerrors.ActorError
ChargeGas(uint64) aerrors.ActorError
}
82 changes: 63 additions & 19 deletions chain/vm/vm.go
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,10 @@ import (

var log = logging.Logger("vm")

const (
gasFundTransfer = 10
)

type VMContext struct {
ctx context.Context

Expand All @@ -33,6 +37,9 @@ type VMContext struct {
height uint64
cst *hamt.CborIpldStore

gasAvailable types.BigInt
gasUsed types.BigInt

// root cid of the state of the actor this invocation will be on
sroot cid.Cid

Expand Down Expand Up @@ -94,7 +101,7 @@ func (vmc *VMContext) Origin() address.Address {

// Send allows the current execution context to invoke methods on other actors in the system
func (vmc *VMContext) Send(to address.Address, method uint64, value types.BigInt, params []byte) ([]byte, aerrors.ActorError) {
ctx, span := trace.StartSpan(vmc.ctx, "vm.send")
ctx, span := trace.StartSpan(vmc.ctx, "vmc.Send")
defer span.End()
if span.IsRecordingEvents() {
span.AddAttributes(
Expand All @@ -105,14 +112,15 @@ func (vmc *VMContext) Send(to address.Address, method uint64, value types.BigInt
}

msg := &types.Message{
From: vmc.msg.To,
To: to,
Method: method,
Value: value,
Params: params,
From: vmc.msg.To,
To: to,
Method: method,
Value: value,
Params: params,
GasLimit: vmc.gasAvailable,
}

ret, err, _ := vmc.vm.send(ctx, vmc.origin, msg)
ret, err, _ := vmc.vm.send(ctx, msg, vmc)
return ret, err
}

Expand All @@ -122,7 +130,16 @@ func (vmc *VMContext) BlockHeight() uint64 {
}

func (vmc *VMContext) GasUsed() types.BigInt {
return types.NewInt(0)
return vmc.gasUsed
}

func (vmc *VMContext) ChargeGas(amount uint64) aerrors.ActorError {
toUse := types.NewInt(amount)
vmc.gasUsed = types.BigAdd(vmc.gasUsed, toUse)
if types.BigCmp(vmc.gasUsed, vmc.gasAvailable) > 0 {
return aerrors.Newf(254, "not enough gas: used=%s, available=%s", vmc.gasUsed, vmc.gasAvailable)
}
return nil
}

func (vmc *VMContext) StateTree() (types.StateTree, aerrors.ActorError) {
Expand Down Expand Up @@ -171,7 +188,7 @@ func (vmctx *VMContext) resolveToKeyAddr(addr address.Address) (address.Address,
return aast.Address, nil
}

func (vm *VM) makeVMContext(ctx context.Context, sroot cid.Cid, origin address.Address, msg *types.Message) *VMContext {
func (vm *VM) makeVMContext(ctx context.Context, sroot cid.Cid, msg *types.Message, origin address.Address, usedGas types.BigInt) *VMContext {

return &VMContext{
ctx: ctx,
Expand All @@ -186,6 +203,9 @@ func (vm *VM) makeVMContext(ctx context.Context, sroot cid.Cid, origin address.A
cst: vm.cst,
head: sroot,
},

gasUsed: usedGas,
gasAvailable: msg.GasLimit,
}
}

Expand Down Expand Up @@ -225,7 +245,8 @@ type ApplyRet struct {
ActorErr aerrors.ActorError
}

func (vm *VM) send(ctx context.Context, origin address.Address, msg *types.Message) ([]byte, aerrors.ActorError, *VMContext) {
func (vm *VM) send(ctx context.Context, msg *types.Message, parent *VMContext) ([]byte, aerrors.ActorError, *VMContext) {

st := vm.cstate
fromActor, err := st.GetActor(msg.From)
if err != nil {
Expand All @@ -245,11 +266,30 @@ func (vm *VM) send(ctx context.Context, origin address.Address, msg *types.Messa
}
}

if err := DeductFunds(fromActor, msg.Value); err != nil {
return nil, aerrors.Absorb(err, 1, "failed to deduct funds"), nil
gasUsed := types.NewInt(0)
origin := msg.From
if parent != nil {
gasUsed = parent.gasUsed
origin = parent.origin
}
DepositFunds(toActor, msg.Value)
vmctx := vm.makeVMContext(ctx, toActor.Head, origin, msg)
vmctx := vm.makeVMContext(ctx, toActor.Head, msg, origin, gasUsed)
if parent != nil {
defer func() {
parent.gasUsed = vmctx.gasUsed
}()
}

if types.BigCmp(msg.Value, types.NewInt(0)) != 0 {
if aerr := vmctx.ChargeGas(gasFundTransfer); aerr != nil {
return nil, aerrors.Wrap(aerr, "sending funds"), nil
}

if err := DeductFunds(fromActor, msg.Value); err != nil {
return nil, aerrors.Absorb(err, 1, "failed to deduct funds"), nil
}
DepositFunds(toActor, msg.Value)
}

if msg.Method != 0 {
ret, err := vm.Invoke(toActor, vmctx, msg.Method, msg.Params)
toActor.Head = vmctx.Storage().GetHead()
Expand All @@ -269,7 +309,7 @@ func checkMessage(msg *types.Message) error {
}

if msg.Value == types.EmptyInt {
return xerrors.Errorf("message gas no gas price set")
return xerrors.Errorf("message no value set")
}

return nil
Expand Down Expand Up @@ -306,17 +346,21 @@ func (vm *VM) ApplyMessage(ctx context.Context, msg *types.Message) (*ApplyRet,
return nil, xerrors.Errorf("invalid nonce (got %d, expected %d)", msg.Nonce, fromActor.Nonce)
}
fromActor.Nonce++
ret, actorErr, vmctx := vm.send(ctx, msg.From, msg)

ret, actorErr, vmctx := vm.send(ctx, msg, nil)

var errcode uint8
var gasUsed types.BigInt
if errcode = aerrors.RetCode(actorErr); errcode != 0 {
gasUsed = msg.GasLimit
// revert all state changes since snapshot
if err := st.Revert(); err != nil {
return nil, xerrors.Errorf("revert state failed: %w", err)
}
} else {
// refund unused gas
refund := types.BigMul(types.BigSub(msg.GasLimit, vmctx.GasUsed()), msg.GasPrice)
gasUsed = vmctx.GasUsed()
refund := types.BigMul(types.BigSub(msg.GasLimit, gasUsed), msg.GasPrice)
DepositFunds(fromActor, refund)
}

Expand All @@ -325,14 +369,14 @@ func (vm *VM) ApplyMessage(ctx context.Context, msg *types.Message) (*ApplyRet,
return nil, xerrors.Errorf("getting block miner actor (%s) failed: %w", vm.blockMiner, err)
}

gasReward := types.BigMul(msg.GasPrice, vmctx.GasUsed())
gasReward := types.BigMul(msg.GasPrice, gasUsed)
DepositFunds(miner, gasReward)

return &ApplyRet{
MessageReceipt: types.MessageReceipt{
ExitCode: errcode,
Return: ret,
GasUsed: vmctx.GasUsed(),
GasUsed: gasUsed,
},
ActorErr: actorErr,
}, nil
Expand Down
2 changes: 0 additions & 2 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,6 @@ require (
contrib.go.opencensus.io/exporter/jaeger v0.1.0
github.com/BurntSushi/toml v0.3.1
github.com/filecoin-project/go-bls-sigs v0.0.0-20190718224239-4bc4b8a7bbf8
github.com/filecoin-project/go-filecoin v0.0.1
github.com/filecoin-project/go-leb128 v0.0.0-20190212224330-8d79a5489543
github.com/filecoin-project/go-sectorbuilder v0.0.0-00010101000000-000000000000
github.com/gbrlsnchs/jwt/v3 v3.0.0-beta.1
Expand Down Expand Up @@ -61,7 +60,6 @@ require (
github.com/multiformats/go-multihash v0.0.6
github.com/pkg/errors v0.8.1
github.com/polydawn/refmt v0.0.0-20190809202753-05966cbd336a
github.com/prometheus/common v0.2.0
github.com/smartystreets/assertions v1.0.1 // indirect
github.com/smartystreets/goconvey v0.0.0-20190710185942-9d28bd7c0945 // indirect
github.com/stretchr/testify v1.3.0
Expand Down
Loading

0 comments on commit 5d7c20c

Please sign in to comment.