diff --git a/packages/isc/sandbox_interface.go b/packages/isc/sandbox_interface.go index b939155e00..2334737811 100644 --- a/packages/isc/sandbox_interface.go +++ b/packages/isc/sandbox_interface.go @@ -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 { diff --git a/packages/testutil/testdbhash/TestStorageContract.hex b/packages/testutil/testdbhash/TestStorageContract.hex index b72ef8ed3b..bdb1f9f770 100644 --- a/packages/testutil/testdbhash/TestStorageContract.hex +++ b/packages/testutil/testdbhash/TestStorageContract.hex @@ -1 +1 @@ -0xf7c89a451c83d8d59b4ec7d6904a8421166463bd4b28feeffe3362313b3ee6d4 +0xa487f3801a48076cae3d99370a55398a401d2716893841e543165ccce74c8b2b diff --git a/packages/vm/core/accounts/impl.go b/packages/vm/core/accounts/impl.go index c51423b47d..85ae6b7f41 100644 --- a/packages/vm/core/accounts/impl.go +++ b/packages/vm/core/accounts/impl.go @@ -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 } diff --git a/packages/vm/core/evm/evmimpl/impl.go b/packages/vm/core/evm/evmimpl/impl.go index b45e0333ff..76d18cb095 100644 --- a/packages/vm/core/evm/evmimpl/impl.go +++ b/packages/vm/core/evm/evmimpl/impl.go @@ -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 @@ -442,6 +442,7 @@ 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") @@ -449,18 +450,24 @@ func newL1Deposit(ctx isc.Sandbox) dict.Dict { // 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 + + 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) }) diff --git a/packages/vm/core/evm/evmnames/evmnames.go b/packages/vm/core/evm/evmnames/evmnames.go index 4ccf601c1d..bcbd606ffd 100644 --- a/packages/vm/core/evm/evmnames/evmnames.go +++ b/packages/vm/core/evm/evmnames/evmnames.go @@ -42,4 +42,6 @@ const ( FieldNFTCollectionID = "C" FieldFoundryTokenScheme = "T" FieldTargetAddress = "A" + + FieldAgentIDDepositOriginator = "l" ) diff --git a/packages/vm/core/evm/evmtest/evm_test.go b/packages/vm/core/evm/evmtest/evm_test.go index dd51437fd1..6ac1c15f5d 100644 --- a/packages/vm/core/evm/evmtest/evm_test.go +++ b/packages/vm/core/evm/evmtest/evm_test.go @@ -7,6 +7,7 @@ import ( "bytes" "encoding/json" "fmt" + "io" "math" "math/big" "strings" @@ -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" @@ -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) @@ -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 ( + 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) } diff --git a/packages/vm/core/evm/interface.go b/packages/vm/core/evm/interface.go index 69f9cee331..cb3a48da6c 100644 --- a/packages/vm/core/evm/interface.go +++ b/packages/vm/core/evm/interface.go @@ -55,6 +55,8 @@ const ( FieldNFTCollectionID = evmnames.FieldNFTCollectionID // NFTID FieldFoundryTokenScheme = evmnames.FieldFoundryTokenScheme FieldTargetAddress = evmnames.FieldTargetAddress + + FieldAgentIDDepositOriginator = evmnames.FieldAgentIDDepositOriginator ) const ( diff --git a/packages/vm/vmimpl/internal.go b/packages/vm/vmimpl/internal.go index 5648f6ddfd..9c30b3520d 100644 --- a/packages/vm/vmimpl/internal.go +++ b/packages/vm/vmimpl/internal.go @@ -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