Skip to content

Commit

Permalink
Merge pull request #3002 from jorgemmsilva/fix/evm-l1-deposit-receipt
Browse files Browse the repository at this point in the history
fix: evm l1 deposit receipt
  • Loading branch information
jorgemmsilva authored Oct 25, 2023
2 parents 78bf3f5 + 0666326 commit 7825645
Show file tree
Hide file tree
Showing 8 changed files with 72 additions and 26 deletions.
2 changes: 1 addition & 1 deletion packages/isc/sandbox_interface.go
Original file line number Diff line number Diff line change
Expand Up @@ -148,7 +148,7 @@ type Privileged interface {
SendOnBehalfOf(caller ContractIdentity, metadata RequestParameters)
}

type CoreCallbackFunc func(contractPartition kv.KVStore)
type CoreCallbackFunc func(contractPartition kv.KVStore, gasBurned uint64)

// RequestParameters represents parameters of the on-ledger request. The output is build from these parameters
type RequestParameters struct {
Expand Down
2 changes: 1 addition & 1 deletion packages/testutil/testdbhash/TestStorageContract.hex
Original file line number Diff line number Diff line change
@@ -1 +1 @@
0xf7c89a451c83d8d59b4ec7d6904a8421166463bd4b28feeffe3362313b3ee6d4
0xa487f3801a48076cae3d99370a55398a401d2716893841e543165ccce74c8b2b
30 changes: 17 additions & 13 deletions packages/vm/core/accounts/impl.go
Original file line number Diff line number Diff line change
Expand Up @@ -69,23 +69,27 @@ func deposit(ctx isc.Sandbox) dict.Dict {
// Params:
// - ParamAgentID. AgentID. Required
func transferAllowanceTo(ctx isc.Sandbox) dict.Dict {
ctx.Log().Debugf("accounts.transferAllowanceTo.begin -- %s", ctx.AllowanceAvailable())
targetAccount := ctx.Params().MustGetAgentID(ParamAgentID)
allowance := ctx.AllowanceAvailable().Clone()
ctx.TransferAllowedFunds(targetAccount)
if targetAccount.Kind() == isc.AgentIDKindEthereumAddress {
evmAcc := targetAccount.(*isc.EthereumAddressAgentID).EthAddress().Bytes()
// issue an "custom" etherum tx so the funds appear on the explorer
ctx.Call(
evm.Contract.Hname(),
evm.FuncNewL1Deposit.Hname(),
dict.Dict{
evm.FieldAddress: evmAcc,
evm.FieldAssets: allowance.Bytes(),
},
nil,
)

if targetAccount.Kind() != isc.AgentIDKindEthereumAddress {
return nil // done
}
if !ctx.Caller().Equals(ctx.Request().SenderAccount()) {
return nil // only issue "custom EVM tx" when this function is called directly by the request sender
}
// issue a "custom EVM tx" so the funds appear on the explorer
ctx.Call(
evm.Contract.Hname(),
evm.FuncNewL1Deposit.Hname(),
dict.Dict{
evm.FieldAddress: targetAccount.(*isc.EthereumAddressAgentID).EthAddress().Bytes(),
evm.FieldAssets: allowance.Bytes(),
evm.FieldAgentIDDepositOriginator: ctx.Caller().Bytes(),
},
nil,
)
ctx.Log().Debugf("accounts.transferAllowanceTo.success: target: %s\n%s", targetAccount, ctx.AllowanceAvailable())
return nil
}
Expand Down
21 changes: 14 additions & 7 deletions packages/vm/core/evm/evmimpl/impl.go
Original file line number Diff line number Diff line change
Expand Up @@ -154,7 +154,7 @@ func applyTransaction(ctx isc.Sandbox) dict.Dict {

// make sure we always store the EVM tx/receipt in the BlockchainDB, even
// if the ISC request is reverted
ctx.Privileged().OnWriteReceipt(func(evmPartition kv.KVStore) {
ctx.Privileged().OnWriteReceipt(func(evmPartition kv.KVStore, _ uint64) {
saveExecutedTx(evmPartition, chainInfo, tx, receipt)
})
// revert the changes in the state / txbuilder in case of error
Expand Down Expand Up @@ -442,25 +442,32 @@ func newL1Deposit(ctx isc.Sandbox) dict.Dict {
// can only be called from the accounts contract
ctx.RequireCaller(isc.NewContractAgentID(ctx.ChainID(), accounts.Contract.Hname()))
params := ctx.Params()
agentIDBytes := params.MustGetBytes(evm.FieldAgentIDDepositOriginator)
addr := common.BytesToAddress(params.MustGetBytes(evm.FieldAddress))
assets, err := isc.AssetsFromBytes(params.MustGetBytes(evm.FieldAssets))
ctx.RequireNoError(err, "unable to parse assets from params")

// create a fake tx so that the deposit is visible by the EVM
value := util.BaseTokensDecimalsToEthereumDecimals(assets.BaseTokens, newEmulatorContext(ctx).BaseTokensDecimals())
nonce := uint64(0)
tx := types.NewTransaction(nonce, addr, value, 0, util.Big0, assets.Bytes())
// encode the txdata as <AgentID sender>+<Assets>
txData := []byte{}
txData = append(txData, agentIDBytes...)
txData = append(txData, assets.Bytes()...)
tx := types.NewTransaction(nonce, addr, value, 0, util.Big0, txData)

// create a fake receipt
chainInfo := ctx.ChainInfo()
receipt := &types.Receipt{
Type: types.LegacyTxType,
CumulativeGasUsed: createBlockchainDB(ctx.State(), ctx.ChainInfo()).GetPendingCumulativeGasUsed(),
GasUsed: 0,
Logs: make([]*types.Log, 0),
Type: types.LegacyTxType,
Logs: make([]*types.Log, 0),
Status: types.ReceiptStatusSuccessful,
}
receipt.Bloom = types.CreateBloom(types.Receipts{receipt})

ctx.Privileged().OnWriteReceipt(func(evmPartition kv.KVStore) {
ctx.Privileged().OnWriteReceipt(func(evmPartition kv.KVStore, gasBurned uint64) {
receipt.GasUsed = gas.ISCGasBurnedToEVM(gasBurned, &chainInfo.GasFeePolicy.EVMGasRatio)
receipt.CumulativeGasUsed = createBlockchainDB(evmPartition, chainInfo).GetPendingCumulativeGasUsed() + receipt.GasUsed
createBlockchainDB(evmPartition, ctx.ChainInfo()).AddTransaction(tx, receipt)
})

Expand Down
2 changes: 2 additions & 0 deletions packages/vm/core/evm/evmnames/evmnames.go
Original file line number Diff line number Diff line change
Expand Up @@ -42,4 +42,6 @@ const (
FieldNFTCollectionID = "C"
FieldFoundryTokenScheme = "T"
FieldTargetAddress = "A"

FieldAgentIDDepositOriginator = "l"
)
37 changes: 34 additions & 3 deletions packages/vm/core/evm/evmtest/evm_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import (
"bytes"
"encoding/json"
"fmt"
"io"
"math"
"math/big"
"strings"
Expand Down Expand Up @@ -40,6 +41,7 @@ import (
"github.com/iotaledger/wasp/packages/testutil/testdbhash"
"github.com/iotaledger/wasp/packages/testutil/testmisc"
"github.com/iotaledger/wasp/packages/util"
"github.com/iotaledger/wasp/packages/util/rwutil"
"github.com/iotaledger/wasp/packages/vm"
"github.com/iotaledger/wasp/packages/vm/core/accounts"
"github.com/iotaledger/wasp/packages/vm/core/evm/iscmagic"
Expand Down Expand Up @@ -2045,7 +2047,16 @@ func TestEmitEventAndRevert(t *testing.T) {
func TestL1DepositEVM(t *testing.T) {
env := InitEVM(t)
// ensure that after a deposit to an EVM account, there is a tx/receipt for it to be auditable on the EVM side
_, ethAddr := env.Chain.NewEthereumAccountWithL2Funds()
wallet, l1Addr := env.solo.NewKeyPairWithFunds()
_, ethAddr := solo.NewEthereumAccount()
amount := 1 * isc.Million
err := env.Chain.TransferAllowanceTo(
isc.NewAssetsBaseTokens(amount),
isc.NewEthereumAddressAgentID(env.Chain.ID(), ethAddr),
wallet,
)
require.NoError(t, err)

bal, err := env.Chain.EVM().Balance(ethAddr, nil)
require.NoError(t, err)

Expand All @@ -2058,6 +2069,26 @@ func TestL1DepositEVM(t *testing.T) {
require.True(t, ethAddr == *tx.To())
require.Zero(t, tx.Value().Cmp(bal))

rec := env.Chain.EVM().TransactionReceipt(tx.Hash())
require.NotNil(t, rec)
// assert txData has the expected information (<agentID sender> + assets)
buf := (bytes.NewReader(tx.Data()))
rr := rwutil.NewReader(buf)
a := isc.AgentIDFromReader(rr)
require.True(t, a.Equals(isc.NewAddressAgentID(l1Addr)))
var assets isc.Assets
assets.Read(buf)
n, err := buf.Read([]byte{})
require.Zero(t, n)
require.ErrorIs(t, err, io.EOF)

require.EqualValues(t,
util.EthereumDecimalsToBaseTokenDecimals(bal, parameters.L1().BaseToken.Decimals),
assets.BaseTokens)

evmRec := env.Chain.EVM().TransactionReceipt(tx.Hash())
require.NotNil(t, evmRec)
require.Equal(t, types.ReceiptStatusSuccessful, evmRec.Status)
iscRec := env.Chain.LastReceipt()
feePolicy := env.Chain.GetGasFeePolicy()
expectedGas := gas.ISCGasBudgetToEVM(iscRec.GasBurned, &feePolicy.EVMGasRatio)
require.EqualValues(t, expectedGas, evmRec.GasUsed)
}
2 changes: 2 additions & 0 deletions packages/vm/core/evm/interface.go
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,8 @@ const (
FieldNFTCollectionID = evmnames.FieldNFTCollectionID // NFTID
FieldFoundryTokenScheme = evmnames.FieldFoundryTokenScheme
FieldTargetAddress = evmnames.FieldTargetAddress

FieldAgentIDDepositOriginator = evmnames.FieldAgentIDDepositOriginator
)

const (
Expand Down
2 changes: 1 addition & 1 deletion packages/vm/vmimpl/internal.go
Original file line number Diff line number Diff line change
Expand Up @@ -170,7 +170,7 @@ func (reqctx *requestContext) writeReceiptToBlockLog(vmError *isc.VMError) *bloc
}
for _, f := range reqctx.onWriteReceipt {
reqctx.callCore(corecontracts.All[f.contract], func(s kv.KVStore) {
f.callback(s)
f.callback(s, receipt.GasBurned)
})
}
return receipt
Expand Down

0 comments on commit 7825645

Please sign in to comment.