Skip to content

Commit

Permalink
fix(vm): prevent the sender from leaving not enough for gas in account
Browse files Browse the repository at this point in the history
  • Loading branch information
dessaya committed Mar 2, 2023
1 parent 70359b0 commit 4fbda50
Show file tree
Hide file tree
Showing 5 changed files with 52 additions and 20 deletions.
2 changes: 0 additions & 2 deletions packages/isc/sandbox_interface.go
Original file line number Diff line number Diff line change
Expand Up @@ -133,8 +133,6 @@ type Privileged interface {
SubscribeBlockContext(openFunc Hname, closeFunc Hname)
SetBlockContext(bctx interface{})
BlockContext() interface{}
// the amount of tokens available to pay for the gas of the current request
TotalGasTokens() *Assets
}

// RequestParameters represents parameters of the on-ledger request. The output is build from these parameters
Expand Down
9 changes: 0 additions & 9 deletions packages/vm/core/evm/evmimpl/internal.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,6 @@ import (
"github.com/iotaledger/wasp/packages/kv/dict"
"github.com/iotaledger/wasp/packages/parameters"
"github.com/iotaledger/wasp/packages/util"
"github.com/iotaledger/wasp/packages/vm"
"github.com/iotaledger/wasp/packages/vm/core/accounts"
"github.com/iotaledger/wasp/packages/vm/core/evm"
"github.com/iotaledger/wasp/packages/vm/core/evm/emulator"
Expand Down Expand Up @@ -324,12 +323,4 @@ func (b *l2Balance) Sub(addr common.Address, amount *big.Int) {
feePolicy := b.getFeePolicy()
tokens := assetsForFeeFromEthereumDecimals(feePolicy, amount)
b.ctx.Privileged().DebitFromAccount(isc.NewEthereumAddressAgentID(addr), tokens)

// assert that remaining tokens in the sender's account are enough to pay for the gas budget
if !b.ctx.HasInAccount(
b.ctx.Request().SenderAccount(),
b.ctx.Privileged().TotalGasTokens(),
) {
panic(vm.ErrNotEnoughTokensLeftForGas)
}
}
8 changes: 0 additions & 8 deletions packages/vm/core/evm/evmimpl/iscmagic_sandbox.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,6 @@ import (

"github.com/iotaledger/wasp/packages/hashing"
"github.com/iotaledger/wasp/packages/isc"
iscvm "github.com/iotaledger/wasp/packages/vm"
"github.com/iotaledger/wasp/packages/vm/core/evm/iscmagic"
)

Expand Down Expand Up @@ -76,13 +75,6 @@ func (h *magicContractHandler) Send(

h.moveAssetsToCommonAccount(req.Assets)

// assert that remaining tokens in the sender's account are enough to pay for the gas budget
if !h.ctx.HasInAccount(
h.ctx.Request().SenderAccount(),
h.ctx.Privileged().TotalGasTokens(),
) {
panic(iscvm.ErrNotEnoughTokensLeftForGas)
}
h.ctx.Send(req)
}

Expand Down
39 changes: 39 additions & 0 deletions packages/vm/core/evm/evmtest/evm_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -519,6 +519,45 @@ func TestSendBaseTokens(t *testing.T) {
require.True(t, getAllowanceTo(iscTest.address).IsEmpty())
}

func TestCannotDepleteAccount(t *testing.T) {
env := initEVM(t)

ethKey, ethAddress := env.soloChain.NewEthereumAccountWithL2Funds()
_, receiver := env.solo.NewKeyPair()

iscTest := env.deployISCTestContract(ethKey)

require.Zero(t, env.solo.L1BaseTokens(receiver))
senderInitialBalance := env.soloChain.L2BaseTokens(isc.NewEthereumAddressAgentID(ethAddress))

// we eill attempt to transfer so much that we are left with no funds for gas
transfer := senderInitialBalance - 300

// allow ISCTest to take the tokens
_, err := env.ISCMagicSandbox(ethKey).callFn(
[]ethCallOptions{{sender: ethKey}},
"allow",
iscTest.address,
iscmagic.WrapISCAssets(isc.NewAssetsBaseTokens(transfer)),
)
require.NoError(t, err)

getAllowanceTo := func(target common.Address) *isc.Assets {
var ret struct{ Allowance iscmagic.ISCAssets }
env.ISCMagicSandbox(ethKey).callView("getAllowanceTo", []interface{}{target}, &ret)
return ret.Allowance.Unwrap()
}

// stored allowance should be == transfer
require.Equal(t, transfer, getAllowanceTo(iscTest.address).BaseTokens)

const allAllowed = uint64(0)
_, err = iscTest.callFn([]ethCallOptions{{
gasLimit: 100_000, // skip estimate gas (which will fail)
}}, "sendBaseTokens", iscmagic.WrapL1Address(receiver), allAllowed)
require.ErrorContains(t, err, vm.ErrNotEnoughTokensLeftForGas.Error())
}

func TestSendNFT(t *testing.T) {
env := initEVM(t)
ethKey, ethAddr := env.soloChain.NewEthereumAccountWithL2Funds()
Expand Down
14 changes: 13 additions & 1 deletion packages/vm/vmcontext/sandbox.go
Original file line number Diff line number Diff line change
Expand Up @@ -157,17 +157,29 @@ func (s *contractSandbox) GasBurnEnable(enable bool) {

func (s *contractSandbox) MustMoveBetweenAccounts(fromAgentID, toAgentID isc.AgentID, assets *isc.Assets) {
s.Ctx.(*VMContext).mustMoveBetweenAccounts(fromAgentID, toAgentID, assets)
s.checkRemainingTokens(fromAgentID)
}

func (s *contractSandbox) DebitFromAccount(agentID isc.AgentID, tokens *isc.Assets) {
s.Ctx.(*VMContext).debitFromAccount(agentID, tokens)
s.checkRemainingTokens(agentID)
}

func (s *contractSandbox) checkRemainingTokens(debitedAccount isc.AgentID) {
// assert that remaining tokens in the sender's account are enough to pay for the gas budget
if debitedAccount.Equals(s.Request().SenderAccount()) && !s.HasInAccount(
debitedAccount,
s.totalGasTokens(),
) {
panic(vm.ErrNotEnoughTokensLeftForGas)
}
}

func (s *contractSandbox) CreditToAccount(agentID isc.AgentID, tokens *isc.Assets) {
s.Ctx.(*VMContext).creditToAccount(agentID, tokens)
}

func (s *contractSandbox) TotalGasTokens() *isc.Assets {
func (s *contractSandbox) totalGasTokens() *isc.Assets {
if s.Ctx.(*VMContext).task.EstimateGasMode {
return isc.NewEmptyAssets()
}
Expand Down

0 comments on commit 4fbda50

Please sign in to comment.