From c3e3718b11129da69dab01302706af568e07df72 Mon Sep 17 00:00:00 2001 From: Yang Hau Date: Fri, 28 Jul 2023 23:21:34 +0300 Subject: [PATCH 1/6] refactor: Change wasmlib.MinGasFee to 100_000 --- packages/wasmvm/wasmlib/as/wasmlib/coreaccounts/params.ts | 4 ++-- packages/wasmvm/wasmlib/as/wasmlib/sandbox.ts | 2 +- packages/wasmvm/wasmlib/go/wasmlib/sandbox.go | 2 +- packages/wasmvm/wasmlib/src/coreaccounts/params.rs | 6 +++--- packages/wasmvm/wasmlib/src/sandbox.rs | 2 +- packages/wasmvm/wasmlib/ts/wasmlib/coreaccounts/params.ts | 4 ++-- packages/wasmvm/wasmlib/ts/wasmlib/sandbox.ts | 2 +- packages/wasmvm/wasmsolo/solocontext.go | 3 +-- 8 files changed, 12 insertions(+), 13 deletions(-) diff --git a/packages/wasmvm/wasmlib/as/wasmlib/coreaccounts/params.ts b/packages/wasmvm/wasmlib/as/wasmlib/coreaccounts/params.ts index 79b189ab03..cfe8d654c9 100644 --- a/packages/wasmvm/wasmlib/as/wasmlib/coreaccounts/params.ts +++ b/packages/wasmvm/wasmlib/as/wasmlib/coreaccounts/params.ts @@ -70,7 +70,7 @@ export class MutableFoundryModifySupplyParams extends wasmtypes.ScProxy { export class ImmutableTransferAccountToChainParams extends wasmtypes.ScProxy { // Optional gas amount to reserve in the allowance for the internal - // call to transferAllowanceTo(). Default 100 (MinGasFee). + // call to transferAllowanceTo(). Default 100_000 (MinGasFee). gasReserve(): wasmtypes.ScImmutableUint64 { return new wasmtypes.ScImmutableUint64(this.proxy.root(sc.ParamGasReserve)); } @@ -78,7 +78,7 @@ export class ImmutableTransferAccountToChainParams extends wasmtypes.ScProxy { export class MutableTransferAccountToChainParams extends wasmtypes.ScProxy { // Optional gas amount to reserve in the allowance for the internal - // call to transferAllowanceTo(). Default 100 (MinGasFee). + // call to transferAllowanceTo(). Default 100_000 (MinGasFee). gasReserve(): wasmtypes.ScMutableUint64 { return new wasmtypes.ScMutableUint64(this.proxy.root(sc.ParamGasReserve)); } diff --git a/packages/wasmvm/wasmlib/as/wasmlib/sandbox.ts b/packages/wasmvm/wasmlib/as/wasmlib/sandbox.ts index 41f4003e42..f5fc596a3d 100644 --- a/packages/wasmvm/wasmlib/as/wasmlib/sandbox.ts +++ b/packages/wasmvm/wasmlib/as/wasmlib/sandbox.ts @@ -2,7 +2,7 @@ // SPDX-License-Identifier: Apache-2.0 // @formatter:off -export const MinGasFee : u64 = 100; +export const MinGasFee : u64 = 100_000; export const StorageDeposit : u64 = 20_000; export const FnAccountID : i32 = -1; diff --git a/packages/wasmvm/wasmlib/go/wasmlib/sandbox.go b/packages/wasmvm/wasmlib/go/wasmlib/sandbox.go index 8bb30f2edc..4a8bbd59d5 100644 --- a/packages/wasmvm/wasmlib/go/wasmlib/sandbox.go +++ b/packages/wasmvm/wasmlib/go/wasmlib/sandbox.go @@ -9,7 +9,7 @@ import ( ) const ( - MinGasFee = uint64(100) + MinGasFee = uint64(100_000) StorageDeposit = uint64(20_000) FnAccountID = int32(-1) diff --git a/packages/wasmvm/wasmlib/src/coreaccounts/params.rs b/packages/wasmvm/wasmlib/src/coreaccounts/params.rs index a8793140b6..a13b12e8d9 100644 --- a/packages/wasmvm/wasmlib/src/coreaccounts/params.rs +++ b/packages/wasmvm/wasmlib/src/coreaccounts/params.rs @@ -6,8 +6,8 @@ #![allow(dead_code)] #![allow(unused_imports)] -use crate::*; use crate::coreaccounts::*; +use crate::*; #[derive(Clone)] pub struct ImmutableFoundryCreateNewParams { @@ -132,7 +132,7 @@ impl ImmutableTransferAccountToChainParams { } // Optional gas amount to reserve in the allowance for the internal - // call to transferAllowanceTo(). Default 100 (MinGasFee). + // call to transferAllowanceTo(). Default 100_000 (MinGasFee). pub fn gas_reserve(&self) -> ScImmutableUint64 { ScImmutableUint64::new(self.proxy.root(PARAM_GAS_RESERVE)) } @@ -145,7 +145,7 @@ pub struct MutableTransferAccountToChainParams { impl MutableTransferAccountToChainParams { // Optional gas amount to reserve in the allowance for the internal - // call to transferAllowanceTo(). Default 100 (MinGasFee). + // call to transferAllowanceTo(). Default 100_000 (MinGasFee). pub fn gas_reserve(&self) -> ScMutableUint64 { ScMutableUint64::new(self.proxy.root(PARAM_GAS_RESERVE)) } diff --git a/packages/wasmvm/wasmlib/src/sandbox.rs b/packages/wasmvm/wasmlib/src/sandbox.rs index c76e995001..de92880bbf 100644 --- a/packages/wasmvm/wasmlib/src/sandbox.rs +++ b/packages/wasmvm/wasmlib/src/sandbox.rs @@ -8,7 +8,7 @@ use crate::host::*; use crate::wasmrequests::*; // @formatter:off -pub const MIN_GAS_FEE : u64 = 100; +pub const MIN_GAS_FEE : u64 = 100_000; pub const STORAGE_DEPOSIT : u64 = 20_000; pub const FN_ACCOUNT_ID : i32 = -1; diff --git a/packages/wasmvm/wasmlib/ts/wasmlib/coreaccounts/params.ts b/packages/wasmvm/wasmlib/ts/wasmlib/coreaccounts/params.ts index 79b189ab03..cfe8d654c9 100644 --- a/packages/wasmvm/wasmlib/ts/wasmlib/coreaccounts/params.ts +++ b/packages/wasmvm/wasmlib/ts/wasmlib/coreaccounts/params.ts @@ -70,7 +70,7 @@ export class MutableFoundryModifySupplyParams extends wasmtypes.ScProxy { export class ImmutableTransferAccountToChainParams extends wasmtypes.ScProxy { // Optional gas amount to reserve in the allowance for the internal - // call to transferAllowanceTo(). Default 100 (MinGasFee). + // call to transferAllowanceTo(). Default 100_000 (MinGasFee). gasReserve(): wasmtypes.ScImmutableUint64 { return new wasmtypes.ScImmutableUint64(this.proxy.root(sc.ParamGasReserve)); } @@ -78,7 +78,7 @@ export class ImmutableTransferAccountToChainParams extends wasmtypes.ScProxy { export class MutableTransferAccountToChainParams extends wasmtypes.ScProxy { // Optional gas amount to reserve in the allowance for the internal - // call to transferAllowanceTo(). Default 100 (MinGasFee). + // call to transferAllowanceTo(). Default 100_000 (MinGasFee). gasReserve(): wasmtypes.ScMutableUint64 { return new wasmtypes.ScMutableUint64(this.proxy.root(sc.ParamGasReserve)); } diff --git a/packages/wasmvm/wasmlib/ts/wasmlib/sandbox.ts b/packages/wasmvm/wasmlib/ts/wasmlib/sandbox.ts index 036cf03c3a..8edcf89e3e 100644 --- a/packages/wasmvm/wasmlib/ts/wasmlib/sandbox.ts +++ b/packages/wasmvm/wasmlib/ts/wasmlib/sandbox.ts @@ -2,7 +2,7 @@ // SPDX-License-Identifier: Apache-2.0 // @formatter:off -export const MinGasFee : u64 = 100n; +export const MinGasFee : u64 = 100_000n; export const StorageDeposit : u64 = 20_000n; export const FnAccountID : i32 = -1; diff --git a/packages/wasmvm/wasmsolo/solocontext.go b/packages/wasmvm/wasmsolo/solocontext.go index 313c7b5a85..d07b688152 100644 --- a/packages/wasmvm/wasmsolo/solocontext.go +++ b/packages/wasmvm/wasmsolo/solocontext.go @@ -51,7 +51,6 @@ var ( ) const ( - MinGasFee = 100 L2FundsAgent = 10 * isc.Million L2FundsContract = 10 * isc.Million L2FundsCreator = 20 * isc.Million @@ -406,7 +405,7 @@ func (ctx *SoloContext) MintNFT(agent *SoloAgent, metadata []byte) wasmtypes.ScN // tokens in its address and pre-deposits 10Mi into the corresponding chain account func (ctx *SoloContext) NewSoloAgent(name string) *SoloAgent { agent := NewSoloAgent(ctx.Chain.Env, name) - ctx.Chain.MustDepositBaseTokensToL2(L2FundsAgent+MinGasFee, agent.Pair) + ctx.Chain.MustDepositBaseTokensToL2(L2FundsAgent+wasmlib.MinGasFee, agent.Pair) return agent } From b04f34114d076c8a46811cf68d0bdffa942745ff Mon Sep 17 00:00:00 2001 From: Yang Hau Date: Fri, 28 Jul 2023 23:52:46 +0300 Subject: [PATCH 2/6] feat: Change gas for emit event as linear --- packages/vm/gas/gas.md | 4 ++-- packages/vm/gas/table.go | 8 ++++---- packages/vm/vmimpl/sandbox.go | 2 +- tools/wasp-cli/authentication/login.go | 3 ++- 4 files changed, 9 insertions(+), 8 deletions(-) diff --git a/packages/vm/gas/gas.md b/packages/vm/gas/gas.md index 36bf5c8d8c..c02538227d 100644 --- a/packages/vm/gas/gas.md +++ b/packages/vm/gas/gas.md @@ -11,13 +11,13 @@ Current gas costs are still experimental and will change. | GetBalance | 20 | get balance of account on the chain | | BurnCodeGetNFTData | 10 | get data about the NFT (issuer/metadata) | | CallContract | 10 | call a target (another SC in the same chain) | -| EmitEventFixed | 10 | emit event | +| EmitEvent | 1*B | emit event (B = number of bytes) | | GetAllowance | 10 | get allowance | | TransferAllowance | 10 | transfer allowance | | BurnCodeEstimateStorageDepositCost | 5 | estimate the storage deposit cost of a L1 request to be sent | | SendL1Request | 200*N | send a L1 transaction (N = number of issued txs in the current call) | | DeployContract | 10 | deploy a contract | -| Storage | 1*B | storage (B = number of bytes) | +| Storage | 55*B | storage (B = number of bytes) | | ReadFromState | 1*(B/100) | read from state (B = number of bytes, adjusted in the call) | | Wasm | X | wasm code execution (X = gas returnted by WASM VM) | | UtilsHashingBlake2b | 5*B | blake2b hash function (B = number of bytes) | diff --git a/packages/vm/gas/table.go b/packages/vm/gas/table.go index 9499e0be75..695f54b88a 100644 --- a/packages/vm/gas/table.go +++ b/packages/vm/gas/table.go @@ -14,7 +14,7 @@ const ( BurnCodeGetNFTData BurnCodeCallContract BurnCodeDeployContract - BurnCodeEmitEventFixed + BurnCodeEmitEvent1P BurnCodeTransferAllowance BurnCodeEstimateStorageDepositCost BurnCodeSendL1Request @@ -47,13 +47,13 @@ var burnTable = BurnTable{ BurnCodeGetBalance: {"balance", constValue(20)}, BurnCodeGetNFTData: {"nft data", constValue(10)}, BurnCodeCallContract: {"call", constValue(100)}, - BurnCodeEmitEventFixed: {"event", constValue(10)}, + BurnCodeEmitEvent1P: {"event", linear(1)}, // 1 gas per byte BurnCodeGetAllowance: {"allowance", constValue(10)}, BurnCodeTransferAllowance: {"transfer", constValue(10)}, BurnCodeEstimateStorageDepositCost: {"storage deposit estimate", constValue(5)}, BurnCodeSendL1Request: {"send", linear(Coef1Send)}, BurnCodeDeployContract: {"deploy", constValue(10)}, - BurnCodeStorage1P: {"storage", linear(1)}, // 1 gas per byte + BurnCodeStorage1P: {"storage", linear(55)}, // 55 gas per byte BurnCodeReadFromState1P: {"state read", linear(1)}, BurnCodeWasm1P: {"wasm", linear(1)}, BurnCodeUtilsHashingBlake2b: {"blake2b", constValue(50)}, @@ -66,7 +66,7 @@ var burnTable = BurnTable{ BurnCodeUtilsBLSValidSignature: {"bls valid", constValue(2000)}, BurnCodeUtilsBLSAddrFromPubKey: {"bls addr", constValue(50)}, BurnCodeUtilsBLSAggregateBLS1P: {"bls aggregate", linear(CoefBLSAggregate)}, - BurnCodeMinimumGasPerRequest1P: {"minimum gas per request", minBurn(10000)}, // TODO maybe make it configurable (gov contract?) + BurnCodeMinimumGasPerRequest1P: {"minimum gas per request", minBurn(10000)}, // TODO maybe make it configurable (gov contract?) // FIXME not equal to wasmlib.MinGasFee BurnCodeEVM1P: {"evm", linear(1)}, } diff --git a/packages/vm/vmimpl/sandbox.go b/packages/vm/vmimpl/sandbox.go index 5d81cdea45..db3c7dcff3 100644 --- a/packages/vm/vmimpl/sandbox.go +++ b/packages/vm/vmimpl/sandbox.go @@ -42,7 +42,7 @@ func (s *contractSandbox) DeployContract(programHash hashing.HashValue, name str } func (s *contractSandbox) Event(topic string, payload []byte) { - s.Ctx.GasBurn(gas.BurnCodeEmitEventFixed) + s.Ctx.GasBurn(gas.BurnCodeEmitEvent1P, uint64(len(topic)+len(payload))) hContract := s.reqctx.CurrentContractHname() hex := iotago.EncodeHex(payload) if len(hex) > 80 { diff --git a/tools/wasp-cli/authentication/login.go b/tools/wasp-cli/authentication/login.go index 236c9cba37..18293ce61b 100644 --- a/tools/wasp-cli/authentication/login.go +++ b/tools/wasp-cli/authentication/login.go @@ -37,7 +37,8 @@ func initLoginCmd() *cobra.Command { username = scanner.Text() log.Printf("Password: ") - passwordBytes, err := term.ReadPassword(int(syscall.Stdin)) //nolint:nolintlint,unconvert // int cast is needed for windows + // int cast is needed for windows + passwordBytes, err := term.ReadPassword(int(syscall.Stdin)) //nolint:unconvert if err != nil { panic(err) } From 2c0e690d446440d9e52be6d6edf5c4977a868ebb Mon Sep 17 00:00:00 2001 From: Yang Hau Date: Mon, 31 Jul 2023 10:14:04 +0300 Subject: [PATCH 3/6] fix: Fix 2chain_test error caused by raising gas fee --- .../wasm/testcore/go/testcoreimpl/funcs.go | 5 +- .../testcore/rs/testcoreimpl/src/funcs.rs | 5 +- contracts/wasm/testcore/schema.yaml | 1 + .../wasm/testcore/ts/testcoreimpl/funcs.ts | 5 +- packages/solo/ledgerl1l2.go | 2 +- packages/vm/core/accounts/impl.go | 5 +- .../vm/core/testcore/sbtests/2chains_test.go | 76 +++++++++++-------- .../sbtestsc/impl_withdraw_from_chain.go | 19 +++-- .../testcore/sbtests/sbtestsc/interface.go | 1 + .../wasmlib/go/wasmlib/coreaccounts/params.go | 4 +- .../wasmlib/interfaces/coreaccounts.yaml | 2 +- 11 files changed, 80 insertions(+), 45 deletions(-) diff --git a/contracts/wasm/testcore/go/testcoreimpl/funcs.go b/contracts/wasm/testcore/go/testcoreimpl/funcs.go index 2c02a35b09..9f81be144b 100644 --- a/contracts/wasm/testcore/go/testcoreimpl/funcs.go +++ b/contracts/wasm/testcore/go/testcoreimpl/funcs.go @@ -249,7 +249,10 @@ func funcWithdrawFromChain(ctx wasmlib.ScFuncContext, f *WithdrawFromChainContex // unless absolutely necessary. Better to just make sure that the // storage deposit is large enough, since it will be returned anyway. const gasFee = wasmlib.MinGasFee - const gasReserve = wasmlib.MinGasFee + var gasReserve = wasmlib.MinGasFee + if f.Params.GasReserve().Exists() { + gasReserve = f.Params.GasReserve().Value() + } const storageDeposit = wasmlib.StorageDeposit // note: gasReserve is the gas necessary to run accounts.transferAllowanceTo diff --git a/contracts/wasm/testcore/rs/testcoreimpl/src/funcs.rs b/contracts/wasm/testcore/rs/testcoreimpl/src/funcs.rs index addc5fbf71..d423b9cc51 100644 --- a/contracts/wasm/testcore/rs/testcoreimpl/src/funcs.rs +++ b/contracts/wasm/testcore/rs/testcoreimpl/src/funcs.rs @@ -262,7 +262,10 @@ pub fn func_withdraw_from_chain(ctx: &ScFuncContext, f: &WithdrawFromChainContex // unless absolutely necessary. Better to just make sure that the // storage deposit is large enough, since it will be returned anyway. let gas_fee: u64 = MIN_GAS_FEE; - let gas_reserve: u64 = MIN_GAS_FEE; + let mut gas_reserve: u64 = MIN_GAS_FEE; + if f.params.gas_reserve().exists() { + gas_reserve = f.params.gas_reserve().value(); + } let storage_deposit: u64 = STORAGE_DEPOSIT; // note: gasReserve is the gas necessary to run accounts.transferAllowanceTo diff --git a/contracts/wasm/testcore/schema.yaml b/contracts/wasm/testcore/schema.yaml index 1c8cc9b986..005900148b 100644 --- a/contracts/wasm/testcore/schema.yaml +++ b/contracts/wasm/testcore/schema.yaml @@ -93,6 +93,7 @@ funcs: params: chainID: ChainID baseTokens: Uint64 + gasReserve: Uint64? views: checkContextFromViewEP: diff --git a/contracts/wasm/testcore/ts/testcoreimpl/funcs.ts b/contracts/wasm/testcore/ts/testcoreimpl/funcs.ts index bc6ede268c..756c0f04c0 100644 --- a/contracts/wasm/testcore/ts/testcoreimpl/funcs.ts +++ b/contracts/wasm/testcore/ts/testcoreimpl/funcs.ts @@ -235,7 +235,10 @@ export function funcWithdrawFromChain(ctx: wasmlib.ScFuncContext, f: sc.Withdraw // unless absolutely necessary. Better to just make sure that the // storage deposit is large enough, since it will be returned anyway. const gasFee: u64 = wasmlib.MinGasFee; - const gasReserve: u64 = wasmlib.MinGasFee; + let gasReserve: u64 = wasmlib.MinGasFee; + if (f.params.gasReserve().exists()) { + gasReserve = f.params.gasReserve().value(); + } const storageDeposit: u64 = wasmlib.StorageDeposit; // note: gasReserve is the gas necessary to run accounts.transferAllowanceTo diff --git a/packages/solo/ledgerl1l2.go b/packages/solo/ledgerl1l2.go index ce75ecc12a..f5e2e14457 100644 --- a/packages/solo/ledgerl1l2.go +++ b/packages/solo/ledgerl1l2.go @@ -297,7 +297,7 @@ func (ch *Chain) DestroyTokensOnL1(nativeTokenID iotago.NativeTokenID, amount in return err } -// DepositAssetsToL2 deposits ftokens on user's on-chain account +// DepositAssetsToL2 deposits ftokens on user's on-chain account, if user is nil, then chain owner is assigned func (ch *Chain) DepositAssetsToL2(assets *isc.Assets, user *cryptolib.KeyPair) error { _, err := ch.PostRequestSync( NewCallParams(accounts.Contract.Name, accounts.FuncDeposit.Name). diff --git a/packages/vm/core/accounts/impl.go b/packages/vm/core/accounts/impl.go index 377634e946..b5e2b21a43 100644 --- a/packages/vm/core/accounts/impl.go +++ b/packages/vm/core/accounts/impl.go @@ -174,8 +174,9 @@ func transferAccountToChain(ctx isc.Sandbox) dict.Dict { // save the assets to send to the transfer request, as specified by the allowance assets := allowance.Clone() + defaultMinGasFee := uint64(100_000) // deduct the gas reserve GAS2 from the allowance, if possible - gasReserve := ctx.Params().MustGetUint64(ParamGasReserve, 100) + gasReserve := ctx.Params().MustGetUint64(ParamGasReserve, defaultMinGasFee) if allowance.BaseTokens < gasReserve { panic(ErrNotEnoughAllowance) } @@ -183,7 +184,7 @@ func transferAccountToChain(ctx isc.Sandbox) dict.Dict { // Warning: this will transfer all assets into the accounts core contract's L2 account. // Be sure everything transfers out again, or assets will be stuck forever. - _ = ctx.TransferAllowedFunds(ctx.AccountID()) + ctx.TransferAllowedFunds(ctx.AccountID()) // Send the specified assets, which should include GAS2 and SD, as part of the // accounts.TransferAllowanceTo() request on the origin chain. diff --git a/packages/vm/core/testcore/sbtests/2chains_test.go b/packages/vm/core/testcore/sbtests/2chains_test.go index c9196e49db..cad7a1bc40 100644 --- a/packages/vm/core/testcore/sbtests/2chains_test.go +++ b/packages/vm/core/testcore/sbtests/2chains_test.go @@ -5,7 +5,6 @@ import ( "testing" "time" - "github.com/ethereum/go-ethereum/common/math" "github.com/stretchr/testify/require" "github.com/iotaledger/wasp/packages/isc" @@ -37,7 +36,9 @@ func test2Chains(t *testing.T, w bool) { WithNativeContract(sbtestsc.Processor) chain1 := env.NewChain() chain2, _ := env.NewChainExt(nil, 0, "chain2") - err := chain2.DepositAssetsToL2(isc.NewAssetsBaseTokens(5*isc.Million), nil) + // chain owner deposit base tokens on chain2 + chain2BaseTokenOwnerDeposit := 5 * isc.Million + err := chain2.DepositAssetsToL2(isc.NewAssetsBaseTokens(chain2BaseTokenOwnerDeposit), nil) require.NoError(t, err) chain1.CheckAccountLedger() chain2.CheckAccountLedger() @@ -56,26 +57,26 @@ func test2Chains(t *testing.T, w bool) { chain2.WaitForRequestsMark() // send base tokens to contractAgentID2 (that is an entity of chain2) on chain1 - const baseTokensToSend = 11 * isc.Million const baseTokensCreditedToScOnChain1 = 10 * isc.Million + const creditBaseTokensToSend = baseTokensCreditedToScOnChain1 + wasmlib.MinGasFee _, err = chain1.PostRequestSync(solo.NewCallParams( accounts.Contract.Name, accounts.FuncTransferAllowanceTo.Name, accounts.ParamAgentID, contractAgentID2, ). - AddBaseTokens(baseTokensToSend). + AddBaseTokens(creditBaseTokensToSend). AddAllowanceBaseTokens(baseTokensCreditedToScOnChain1). - WithGasBudget(math.MaxUint64), + WithMaxAffordableGasBudget(), userWallet) require.NoError(t, err) chain1TransferAllowanceReceipt := chain1.LastReceipt() chain1TransferAllowanceGas := chain1TransferAllowanceReceipt.GasFeeCharged - env.AssertL1BaseTokens(userAddress, utxodb.FundsFromFaucetAmount-baseTokensToSend) - chain1.AssertL2BaseTokens(userAgentID, baseTokensToSend-baseTokensCreditedToScOnChain1-chain1TransferAllowanceGas) + env.AssertL1BaseTokens(userAddress, utxodb.FundsFromFaucetAmount-creditBaseTokensToSend) + chain1.AssertL2BaseTokens(userAgentID, creditBaseTokensToSend-baseTokensCreditedToScOnChain1-chain1TransferAllowanceGas) chain1.AssertL2BaseTokens(contractAgentID2, baseTokensCreditedToScOnChain1) - chain1.AssertL2TotalBaseTokens(chain1TotalBaseTokens + baseTokensToSend) - chain1TotalBaseTokens += baseTokensToSend + chain1.AssertL2TotalBaseTokens(chain1TotalBaseTokens + creditBaseTokensToSend) + chain1TotalBaseTokens += creditBaseTokensToSend chain2.AssertL2BaseTokens(userAgentID, 0) chain2.AssertL2BaseTokens(contractAgentID2, 0) @@ -90,49 +91,61 @@ func test2Chains(t *testing.T, w bool) { // make chain2 send a call to chain1 to withdraw base tokens baseTokensToWithdrawFromChain1 := baseTokensCreditedToScOnChain1 - // actual gas fee is less, but always rounded up to this minimum amount - const gasFee = wasmlib.MinGasFee + const gasFee1 = wasmlib.MinGasFee + const gasFee2 = wasmlib.MinGasFee + const withdrawFeeGas = wasmlib.MinGasFee const storageDeposit = wasmlib.StorageDeposit // NOTE: make sure you READ THE DOCS for accounts.transferAccountToChain() // to understand fully how to call it and why. - // reqAllowance is the allowance provided to chain2.testcore.withdrawFromChain(), + // withdrawReqAllowance is the allowance provided to chain2.testcore.withdrawFromChain(), // which needs to be enough to cover any storage deposit along the way and to pay // the gas fees for the chain2.accounts.transferAccountToChain() request and the // chain1.accounts.transferAllowanceTo() request. // note that the storage deposit will be returned in the end - reqAllowance := storageDeposit + gasFee + gasFee + withdrawReqAllowance := storageDeposit + gasFee1 + gasFee2 // also cover gas fee for `FuncWithdrawFromChain` on chain2 - assetsBaseTokens := reqAllowance + isc.Million + withdrawBaseTokensToSend := withdrawReqAllowance + withdrawFeeGas - _, err = chain2.PostRequestSync(solo.NewCallParams(ScName, sbtestsc.FuncWithdrawFromChain.Name, + _, err = chain2.PostRequestSync(solo.NewCallParams( + ScName, sbtestsc.FuncWithdrawFromChain.Name, sbtestsc.ParamChainID, chain1.ChainID, - sbtestsc.ParamBaseTokens, baseTokensToWithdrawFromChain1). - AddBaseTokens(assetsBaseTokens). - WithAllowance(isc.NewAssetsBaseTokens(reqAllowance)). - WithGasBudget(isc.Million), + sbtestsc.ParamBaseTokens, baseTokensToWithdrawFromChain1, + sbtestsc.ParamGasReserve, gasFee2, + ). + AddBaseTokens(withdrawBaseTokensToSend). + WithAllowance(isc.NewAssetsBaseTokens(withdrawReqAllowance)). + WithMaxAffordableGasBudget(), userWallet) require.NoError(t, err) chain2WithdrawFromChainReceipt := chain2.LastReceipt() chain2WithdrawFromChainGas := chain2WithdrawFromChainReceipt.GasFeeCharged + chain2WithdrawFromChainTarget := chain2WithdrawFromChainReceipt.DeserializedRequest().CallTarget() + require.Equal(t, sbtestsc.Contract.Hname(), chain2WithdrawFromChainTarget.Contract) + require.Equal(t, sbtestsc.FuncWithdrawFromChain.Hname(), chain2WithdrawFromChainTarget.EntryPoint) + require.Nil(t, chain2WithdrawFromChainReceipt.Error) + // accounts.FuncTransferAllowanceTo() + // accounts.FuncTransferAccountToChain() require.True(t, chain1.WaitForRequestsThrough(2, 10*time.Second)) + // testcore.FuncWithdrawFromChain() + // accounts.FuncTransferAllowanceTo() require.True(t, chain2.WaitForRequestsThrough(2, 10*time.Second)) chain2TransferAllowanceReceipt := chain2.LastReceipt() - chain2TransferAllowanceGas := chain2TransferAllowanceReceipt.GasFeeCharged + // chain2TransferAllowanceGas := chain2TransferAllowanceReceipt.GasFeeCharged chain2TransferAllowanceTarget := chain2TransferAllowanceReceipt.DeserializedRequest().CallTarget() - require.Equal(t, chain2TransferAllowanceTarget.Contract, accounts.Contract.Hname()) - require.Equal(t, chain2TransferAllowanceTarget.EntryPoint, accounts.FuncTransferAllowanceTo.Hname()) + require.Equal(t, accounts.Contract.Hname(), chain2TransferAllowanceTarget.Contract) + require.Equal(t, accounts.FuncTransferAllowanceTo.Hname(), chain2TransferAllowanceTarget.EntryPoint) require.Nil(t, chain2TransferAllowanceReceipt.Error) chain1TransferAccountToChainReceipt := chain1.LastReceipt() chain1TransferAccountToChainGas := chain1TransferAccountToChainReceipt.GasFeeCharged chain1TransferAccountToChainTarget := chain1TransferAccountToChainReceipt.DeserializedRequest().CallTarget() - require.Equal(t, chain1TransferAccountToChainTarget.Contract, accounts.Contract.Hname()) - require.Equal(t, chain1TransferAccountToChainTarget.EntryPoint, accounts.FuncTransferAccountToChain.Hname()) + require.Equal(t, accounts.Contract.Hname(), chain1TransferAccountToChainTarget.Contract) + require.Equal(t, accounts.FuncTransferAccountToChain.Hname(), chain1TransferAccountToChainTarget.EntryPoint) require.Nil(t, chain1TransferAccountToChainReceipt.Error) fmt.Println("---------------chain1---------------") @@ -141,13 +154,16 @@ func test2Chains(t *testing.T, w bool) { fmt.Println(chain2.DumpAccounts()) fmt.Println("------------------------------------") - env.AssertL1BaseTokens(userAddress, utxodb.FundsFromFaucetAmount-baseTokensToSend-assetsBaseTokens) + // the 2 function call we did above are requests from L1 + env.AssertL1BaseTokens(userAddress, utxodb.FundsFromFaucetAmount-creditBaseTokensToSend-withdrawBaseTokensToSend) + // on chain1 user only made the first transaction + chain1.AssertL2BaseTokens(userAgentID, creditBaseTokensToSend-baseTokensCreditedToScOnChain1-chain1TransferAllowanceGas) - chain1.AssertL2BaseTokens(userAgentID, baseTokensToSend-baseTokensCreditedToScOnChain1-chain1TransferAllowanceGas) - chain1.AssertL2BaseTokens(contractAgentID2, 0) // emptied the account - chain1.AssertL2TotalBaseTokens(chain1TotalBaseTokens + chain1TransferAllowanceGas + chain1TransferAccountToChainGas - chain2TransferAllowanceGas - baseTokensToWithdrawFromChain1) + // FIXME ??? + chain1.AssertL2BaseTokens(contractAgentID2, wasmlib.MinGasFee-chain1TransferAccountToChainGas) + chain1.AssertL2TotalBaseTokens(chain1TotalBaseTokens + withdrawBaseTokensToSend - baseTokensToWithdrawFromChain1 - withdrawReqAllowance) - chain2.AssertL2BaseTokens(userAgentID, assetsBaseTokens-reqAllowance-chain2WithdrawFromChainGas) + chain2.AssertL2BaseTokens(userAgentID, withdrawBaseTokensToSend-withdrawReqAllowance-chain2WithdrawFromChainGas) chain2.AssertL2BaseTokens(contractAgentID2, baseTokensToWithdrawFromChain1+storageDeposit) - chain2.AssertL2TotalBaseTokens(chain2TotalBaseTokens + assetsBaseTokens + baseTokensCreditedToScOnChain1 + chain2TransferAllowanceGas - chain1TransferAllowanceGas - chain1TransferAccountToChainGas) + chain2.AssertL2TotalBaseTokens(baseTokensToWithdrawFromChain1 + chain2TotalBaseTokens + withdrawReqAllowance) } diff --git a/packages/vm/core/testcore/sbtests/sbtestsc/impl_withdraw_from_chain.go b/packages/vm/core/testcore/sbtests/sbtestsc/impl_withdraw_from_chain.go index 2231448a78..35197990a4 100644 --- a/packages/vm/core/testcore/sbtests/sbtestsc/impl_withdraw_from_chain.go +++ b/packages/vm/core/testcore/sbtests/sbtestsc/impl_withdraw_from_chain.go @@ -2,6 +2,7 @@ package sbtestsc import ( "github.com/iotaledger/wasp/packages/isc" + "github.com/iotaledger/wasp/packages/kv/codec" "github.com/iotaledger/wasp/packages/kv/dict" "github.com/iotaledger/wasp/packages/vm/core/accounts" "github.com/iotaledger/wasp/packages/wasmvm/wasmlib/go/wasmlib" @@ -15,9 +16,9 @@ func withdrawFromChain(ctx isc.Sandbox) dict.Dict { withdrawal := params.MustGetUint64(ParamBaseTokens) // if it is not already present in the SC's account the caller should have - // provided enough base tokens to cover the gas fees for the current call, - // and for the storage deposit plus gas fees for the outgoing request to - // accounts.transferAllowanceTo() + // provided enough base tokens to cover the gas fees for the current call + // (should be wasmlib.MinGasFee in default), and for the storage deposit + // plus gas fees for the outgoing request to accounts.transferAllowanceTo() ctx.TransferAllowedFunds(ctx.AccountID()) // This is just a test contract, but normally these numbers should @@ -26,19 +27,25 @@ func withdrawFromChain(ctx isc.Sandbox) dict.Dict { // the costly calculation to determine storage deposit every time // unless absolutely necessary. Better to just make sure that the // storage deposit is large enough, since it will be returned anyway. + // gasFee is for sending FuncTransferAccountToChain() request const gasFee = wasmlib.MinGasFee + // gasReserve is the gas fee for the function all inside FuncTransferAccountToChain() + gasReserve := params.MustGetUint64(ParamGasReserve, wasmlib.MinGasFee) const storageDeposit = wasmlib.StorageDeposit // make sure to send enough to cover the storage deposit and gas fees // the storage deposit will be returned along with the withdrawal ctx.Send(isc.RequestParameters{ TargetAddress: targetChain.AsAddress(), - Assets: isc.NewAssetsBaseTokens(storageDeposit + gasFee + gasFee), + Assets: isc.NewAssetsBaseTokens(storageDeposit + gasFee + gasReserve), Metadata: &isc.SendMetadata{ TargetContract: accounts.Contract.Hname(), EntryPoint: accounts.FuncTransferAccountToChain.Hname(), - GasBudget: gasFee, - Allowance: isc.NewAssetsBaseTokens(withdrawal + storageDeposit + gasFee), + Params: dict.Dict{ + accounts.ParamGasReserve: codec.EncodeUint64(gasReserve), + }, + GasBudget: gasReserve, + Allowance: isc.NewAssetsBaseTokens(withdrawal + storageDeposit + gasReserve), }, }) diff --git a/packages/vm/core/testcore/sbtests/sbtestsc/interface.go b/packages/vm/core/testcore/sbtests/sbtestsc/interface.go index 9ca950b270..6c3746043b 100644 --- a/packages/vm/core/testcore/sbtests/sbtestsc/interface.go +++ b/packages/vm/core/testcore/sbtests/sbtestsc/interface.go @@ -121,6 +121,7 @@ const ( ParamCaller = "caller" ParamChainID = "chainID" ParamChainOwnerID = "chainOwnerID" + ParamGasReserve = "gasReserve" ParamContractID = "contractID" ParamFail = "initFailParam" ParamHnameContract = "hnameContract" diff --git a/packages/wasmvm/wasmlib/go/wasmlib/coreaccounts/params.go b/packages/wasmvm/wasmlib/go/wasmlib/coreaccounts/params.go index 71ca1ee49e..1d47f63f9d 100644 --- a/packages/wasmvm/wasmlib/go/wasmlib/coreaccounts/params.go +++ b/packages/wasmvm/wasmlib/go/wasmlib/coreaccounts/params.go @@ -105,7 +105,7 @@ func NewImmutableTransferAccountToChainParams() ImmutableTransferAccountToChainP } // Optional gas amount to reserve in the allowance for the internal -// call to transferAllowanceTo(). Default 100 (MinGasFee). +// call to transferAllowanceTo(). Default 100_000 (MinGasFee). func (s ImmutableTransferAccountToChainParams) GasReserve() wasmtypes.ScImmutableUint64 { return wasmtypes.NewScImmutableUint64(s.Proxy.Root(ParamGasReserve)) } @@ -115,7 +115,7 @@ type MutableTransferAccountToChainParams struct { } // Optional gas amount to reserve in the allowance for the internal -// call to transferAllowanceTo(). Default 100 (MinGasFee). +// call to transferAllowanceTo(). Default 100_000 (MinGasFee). func (s MutableTransferAccountToChainParams) GasReserve() wasmtypes.ScMutableUint64 { return wasmtypes.NewScMutableUint64(s.Proxy.Root(ParamGasReserve)) } diff --git a/packages/wasmvm/wasmlib/interfaces/coreaccounts.yaml b/packages/wasmvm/wasmlib/interfaces/coreaccounts.yaml index 1eb0cdc360..a3c8bb5c9d 100644 --- a/packages/wasmvm/wasmlib/interfaces/coreaccounts.yaml +++ b/packages/wasmvm/wasmlib/interfaces/coreaccounts.yaml @@ -50,7 +50,7 @@ funcs: transferAccountToChain: params: # Optional gas amount to reserve in the allowance for the internal - # call to transferAllowanceTo(). Default 100 (MinGasFee). + # call to transferAllowanceTo(). Default 100_000 (MinGasFee). gasReserve=g: Uint64? # Transfers the specified allowance from the sender's L2 account From 02047e47a24986a284ee78260c61cc538891397f Mon Sep 17 00:00:00 2001 From: Yang Hau Date: Sun, 6 Aug 2023 22:57:03 +0300 Subject: [PATCH 4/6] test: Fix tests error due to raising gas fee --- packages/chain/cons/cons_test.go | 4 +++- .../testutil/testchain/test_chain_ledger.go | 7 +++++-- packages/vm/core/accounts/impl.go | 4 ++-- packages/vm/core/evm/evmimpl/impl.go | 9 +++++++-- packages/vm/core/evm/evmtest/utils_test.go | 8 +++++++- .../testcore/custom_onledger_requests_test.go | 18 +++++++++++++----- .../vm/core/testcore/sbtests/setup_test.go | 4 +++- 7 files changed, 40 insertions(+), 14 deletions(-) diff --git a/packages/chain/cons/cons_test.go b/packages/chain/cons/cons_test.go index 22f64322bc..487ae531e3 100644 --- a/packages/chain/cons/cons_test.go +++ b/packages/chain/cons/cons_test.go @@ -36,6 +36,7 @@ import ( "github.com/iotaledger/wasp/packages/vm/core/migrations/allmigrations" "github.com/iotaledger/wasp/packages/vm/processors" "github.com/iotaledger/wasp/packages/vm/vmimpl" + "github.com/iotaledger/wasp/packages/wasmvm/wasmlib/go/wasmlib" ) // Here we run a single consensus instance, step by step with @@ -346,7 +347,8 @@ func testChained(t *testing.T, n, f, b int) { inccounter.FuncIncCounter.Hname(), dict.New(), uint64(i*reqPerBlock+ii), - 20000, + // FIXME may user other MinGasFee instead of wasmlib.MinGasFee + wasmlib.MinGasFee, ).Sign(scClient) reqs = append(reqs, scRequest) incTotal++ diff --git a/packages/testutil/testchain/test_chain_ledger.go b/packages/testutil/testchain/test_chain_ledger.go index 983ff15d68..142e45a27b 100644 --- a/packages/testutil/testchain/test_chain_ledger.go +++ b/packages/testutil/testchain/test_chain_ledger.go @@ -21,6 +21,7 @@ import ( "github.com/iotaledger/wasp/packages/vm/core/migrations/allmigrations" "github.com/iotaledger/wasp/packages/vm/core/root" "github.com/iotaledger/wasp/packages/vm/gas" + "github.com/iotaledger/wasp/packages/wasmvm/wasmlib/go/wasmlib" ) //////////////////////////////////////////////////////////////////////////////// @@ -86,7 +87,8 @@ func (tcl *TestChainLedger) MakeTxAccountsDeposit(account *cryptolib.KeyPair) [] Metadata: &isc.SendMetadata{ TargetContract: accounts.Contract.Hname(), EntryPoint: accounts.FuncDeposit.Hname(), - GasBudget: 10_000, + // FIXME may user other MinGasFee instead of wasmlib.MinGasFee + GasBudget: wasmlib.MinGasFee, }, }, }, @@ -117,7 +119,8 @@ func (tcl *TestChainLedger) MakeTxDeployIncCounterContract() []isc.Request { root.ParamName: inccounter.Contract.Name, inccounter.VarCounter: 0, }), - GasBudget: 10_000, + // FIXME may user other MinGasFee instead of wasmlib.MinGasFee + GasBudget: wasmlib.MinGasFee, }, }, }, diff --git a/packages/vm/core/accounts/impl.go b/packages/vm/core/accounts/impl.go index b5e2b21a43..881c9a996d 100644 --- a/packages/vm/core/accounts/impl.go +++ b/packages/vm/core/accounts/impl.go @@ -11,6 +11,7 @@ import ( "github.com/iotaledger/wasp/packages/util" "github.com/iotaledger/wasp/packages/vm" "github.com/iotaledger/wasp/packages/vm/core/errors/coreerrors" + "github.com/iotaledger/wasp/packages/wasmvm/wasmlib/go/wasmlib" ) func CommonAccount() isc.AgentID { @@ -174,9 +175,8 @@ func transferAccountToChain(ctx isc.Sandbox) dict.Dict { // save the assets to send to the transfer request, as specified by the allowance assets := allowance.Clone() - defaultMinGasFee := uint64(100_000) // deduct the gas reserve GAS2 from the allowance, if possible - gasReserve := ctx.Params().MustGetUint64(ParamGasReserve, defaultMinGasFee) + gasReserve := ctx.Params().MustGetUint64(ParamGasReserve, wasmlib.MinGasFee) if allowance.BaseTokens < gasReserve { panic(ErrNotEnoughAllowance) } diff --git a/packages/vm/core/evm/evmimpl/impl.go b/packages/vm/core/evm/evmimpl/impl.go index 3bac58326d..4e3883b967 100644 --- a/packages/vm/core/evm/evmimpl/impl.go +++ b/packages/vm/core/evm/evmimpl/impl.go @@ -29,6 +29,7 @@ import ( "github.com/iotaledger/wasp/packages/vm/core/evm/iscmagic" "github.com/iotaledger/wasp/packages/vm/core/governance" "github.com/iotaledger/wasp/packages/vm/gas" + "github.com/iotaledger/wasp/packages/wasmvm/wasmlib/go/wasmlib" ) var Processor = evm.Contract.Processor(nil, @@ -252,11 +253,15 @@ func registerERC20NativeTokenOnRemoteChain(ctx isc.Sandbox) dict.Dict { evm.FieldTokenDecimals: codec.EncodeUint8(decimals), evm.FieldFoundryTokenScheme: codec.EncodeTokenScheme(tokenScheme), }, + // FIXME why does this gas budget is higher than the allowance below + GasBudget: 5 * wasmlib.MinGasFee, }, } sd := ctx.EstimateRequiredStorageDeposit(req) - ctx.TransferAllowedFunds(ctx.AccountID(), isc.NewAssetsBaseTokens(sd)) - req.Assets.AddBaseTokens(sd) + // this request is sent by contract account, + // so we move enough allowance for the gas fee below in the req.Assets.AddBaseTokens() function call + ctx.TransferAllowedFunds(ctx.AccountID(), isc.NewAssetsBaseTokens(sd+wasmlib.MinGasFee)) + req.Assets.AddBaseTokens(sd + wasmlib.MinGasFee) ctx.Send(req) return nil diff --git a/packages/vm/core/evm/evmtest/utils_test.go b/packages/vm/core/evm/evmtest/utils_test.go index b52c1c735a..465a2ce0a3 100644 --- a/packages/vm/core/evm/evmtest/utils_test.go +++ b/packages/vm/core/evm/evmtest/utils_test.go @@ -33,6 +33,7 @@ import ( "github.com/iotaledger/wasp/packages/vm/core/evm/iscmagic" "github.com/iotaledger/wasp/packages/vm/core/governance" "github.com/iotaledger/wasp/packages/vm/gas" + "github.com/iotaledger/wasp/packages/wasmvm/wasmlib/go/wasmlib" ) type soloChainEnv struct { @@ -370,7 +371,12 @@ func (e *soloChainEnv) registerERC20ExternalNativeToken( evm.FieldTokenTickerSymbol: codec.EncodeString(tokenTickerSymbol), evm.FieldTokenDecimals: codec.EncodeUint8(tokenDecimals), evm.FieldTargetAddress: codec.EncodeAddress(e.soloChain.ChainID.AsAddress()), - }).WithMaxAffordableGasBudget().WithAllowance(isc.NewAssetsBaseTokens(1*isc.Million)), fromChain.OriginatorPrivateKey) + }). + // to cover sd and gas fee for the 'FuncRegisterERC20ExternalNativeToken' func call in 'FuncRegisterERC20NativeTokenOnRemoteChain' + WithAllowance(isc.NewAssetsBaseTokens(2*wasmlib.MinGasFee)). + // FIXME why this gas budget is less than the gas budget of the indirect call FuncRegisterERC20ExternalNativeToken + WithGasBudget(wasmlib.MinGasFee), + fromChain.OriginatorPrivateKey) if err != nil { return ret, err } diff --git a/packages/vm/core/testcore/custom_onledger_requests_test.go b/packages/vm/core/testcore/custom_onledger_requests_test.go index 7eec9e2e02..be269ada30 100644 --- a/packages/vm/core/testcore/custom_onledger_requests_test.go +++ b/packages/vm/core/testcore/custom_onledger_requests_test.go @@ -15,6 +15,8 @@ import ( "github.com/iotaledger/wasp/packages/solo" "github.com/iotaledger/wasp/packages/testutil/testmisc" "github.com/iotaledger/wasp/packages/transaction" + "github.com/iotaledger/wasp/packages/vm/core/accounts" + "github.com/iotaledger/wasp/packages/wasmvm/wasmlib/go/wasmlib" ) func TestNoSenderFeature(t *testing.T) { @@ -37,14 +39,20 @@ func TestNoSenderFeature(t *testing.T) { err = ch.MintTokens(sn, nativeTokenAmount, wallet) require.NoError(t, err) - // withdraw NTs to L1 - req := solo.NewCallParams("accounts", "withdraw"). - AddAllowanceBaseTokens(5 * isc.Million). + // withdraw native tokens to L1 + allowance := 5 * isc.Million + baseTokensToSend := allowance + wasmlib.MinGasFee + _, err = ch.PostRequestOffLedger(solo.NewCallParams( + accounts.Contract.Name, accounts.FuncWithdraw.Name, + ). + AddBaseTokens(baseTokensToSend). + AddAllowanceBaseTokens(allowance). AddAllowanceNativeTokensVect(&iotago.NativeToken{ ID: nativeTokenID, Amount: nativeTokenAmount, - }) - _, err = ch.PostRequestOffLedger(req, wallet) + }). + WithGasBudget(wasmlib.MinGasFee), + wallet) require.NoError(t, err) nft, _, err := ch.Env.MintNFTL1(wallet, addr, []byte("foobar")) diff --git a/packages/vm/core/testcore/sbtests/setup_test.go b/packages/vm/core/testcore/sbtests/setup_test.go index 99e5ba76c0..afe1def52e 100644 --- a/packages/vm/core/testcore/sbtests/setup_test.go +++ b/packages/vm/core/testcore/sbtests/setup_test.go @@ -14,6 +14,7 @@ import ( "github.com/iotaledger/wasp/packages/vm/core/root" "github.com/iotaledger/wasp/packages/vm/core/testcore/sbtests/sbtestsc" "github.com/iotaledger/wasp/packages/wasmvm/wasmhost" + "github.com/iotaledger/wasp/packages/wasmvm/wasmlib/go/wasmlib" ) const ( @@ -50,7 +51,8 @@ func setupDeployer(t *testing.T, ch *solo.Chain) (*cryptolib.KeyPair, isc.AgentI user, userAddr := ch.Env.NewKeyPairWithFunds() ch.Env.AssertL1BaseTokens(userAddr, utxodb.FundsFromFaucetAmount) - err := ch.DepositBaseTokensToL2(10_000, user) + // FIXME may user other MinGasFee instead of wasmlib.MinGasFee + err := ch.DepositBaseTokensToL2(wasmlib.MinGasFee, user) require.NoError(t, err) req := solo.NewCallParams(root.Contract.Name, root.FuncGrantDeployPermission.Name, From 730277a75d8617ceb4bc9a320ea8e3e20e43709d Mon Sep 17 00:00:00 2001 From: Yang Hau Date: Wed, 9 Aug 2023 02:06:05 +0300 Subject: [PATCH 5/6] doc: Add 2chain_test comments --- .../vm/core/testcore/sbtests/2chains_test.go | 33 +++++++++++++------ 1 file changed, 23 insertions(+), 10 deletions(-) diff --git a/packages/vm/core/testcore/sbtests/2chains_test.go b/packages/vm/core/testcore/sbtests/2chains_test.go index cad7a1bc40..1b0a0e960d 100644 --- a/packages/vm/core/testcore/sbtests/2chains_test.go +++ b/packages/vm/core/testcore/sbtests/2chains_test.go @@ -50,6 +50,12 @@ func test2Chains(t *testing.T, w bool) { userAgentID := isc.NewAgentID(userAddress) env.AssertL1BaseTokens(userAddress, utxodb.FundsFromFaucetAmount) + fmt.Println("---------------chain1---------------") + fmt.Println(chain1.DumpAccounts()) + fmt.Println("---------------chain2---------------") + fmt.Println(chain2.DumpAccounts()) + fmt.Println("------------------------------------") + chain1TotalBaseTokens := chain1.L2TotalBaseTokens() chain2TotalBaseTokens := chain2.L2TotalBaseTokens() @@ -92,7 +98,8 @@ func test2Chains(t *testing.T, w bool) { baseTokensToWithdrawFromChain1 := baseTokensCreditedToScOnChain1 const gasFee1 = wasmlib.MinGasFee - const gasFee2 = wasmlib.MinGasFee + // gas reserve for the 'TransferAllowanceTo' func call in 'TransferAccountToChain' func call + const gasReserve = wasmlib.MinGasFee const withdrawFeeGas = wasmlib.MinGasFee const storageDeposit = wasmlib.StorageDeposit @@ -104,7 +111,7 @@ func test2Chains(t *testing.T, w bool) { // the gas fees for the chain2.accounts.transferAccountToChain() request and the // chain1.accounts.transferAllowanceTo() request. // note that the storage deposit will be returned in the end - withdrawReqAllowance := storageDeposit + gasFee1 + gasFee2 + withdrawReqAllowance := storageDeposit + gasFee1 + gasReserve // also cover gas fee for `FuncWithdrawFromChain` on chain2 withdrawBaseTokensToSend := withdrawReqAllowance + withdrawFeeGas @@ -113,7 +120,7 @@ func test2Chains(t *testing.T, w bool) { ScName, sbtestsc.FuncWithdrawFromChain.Name, sbtestsc.ParamChainID, chain1.ChainID, sbtestsc.ParamBaseTokens, baseTokensToWithdrawFromChain1, - sbtestsc.ParamGasReserve, gasFee2, + sbtestsc.ParamGasReserve, gasReserve, ). AddBaseTokens(withdrawBaseTokensToSend). WithAllowance(isc.NewAssetsBaseTokens(withdrawReqAllowance)). @@ -156,14 +163,20 @@ func test2Chains(t *testing.T, w bool) { // the 2 function call we did above are requests from L1 env.AssertL1BaseTokens(userAddress, utxodb.FundsFromFaucetAmount-creditBaseTokensToSend-withdrawBaseTokensToSend) - // on chain1 user only made the first transaction + // on chain1 user only made the first transaction, so it is the same as its balance before 'WithdrawFromChain' function call chain1.AssertL2BaseTokens(userAgentID, creditBaseTokensToSend-baseTokensCreditedToScOnChain1-chain1TransferAllowanceGas) - - // FIXME ??? - chain1.AssertL2BaseTokens(contractAgentID2, wasmlib.MinGasFee-chain1TransferAccountToChainGas) - chain1.AssertL2TotalBaseTokens(chain1TotalBaseTokens + withdrawBaseTokensToSend - baseTokensToWithdrawFromChain1 - withdrawReqAllowance) - + // gasReserve is used for paying the gas fee of the 'TransferAllowanceTo' func call in 'TransferAccountToChain' func call + // So the token left in contractAgentID2 on chain1 is the unused gas fee + chain1.AssertL2BaseTokens(contractAgentID2, gasReserve-chain1TransferAccountToChainGas) + // tokens in 'withdrawBaseTokensToSend' amount are moved with the request from L1 to L2 + // 'withdrawReqAllowance' is is the amount moved from chain1 to chain2 with the request + // 'baseTokensToWithdrawFromChain1' is the amount we assigned to withdraw in 'WithdrawFromChain' func call + chain1.AssertL2TotalBaseTokens(chain1TotalBaseTokens + (withdrawBaseTokensToSend - withdrawReqAllowance - baseTokensToWithdrawFromChain1)) + + // tokens in 'withdrawBaseTokensToSend' amount are moved from L1 to L2 with the 'WithdrawFromChain' func call + // token in 'withdrawReqAllowance' amount are withdrawn by contractAgentID2 + // and 'WithdrawFromChain' func call was sent by user on chain2, so its balance should deduct 'chain2WithdrawFromChainGas' chain2.AssertL2BaseTokens(userAgentID, withdrawBaseTokensToSend-withdrawReqAllowance-chain2WithdrawFromChainGas) chain2.AssertL2BaseTokens(contractAgentID2, baseTokensToWithdrawFromChain1+storageDeposit) - chain2.AssertL2TotalBaseTokens(baseTokensToWithdrawFromChain1 + chain2TotalBaseTokens + withdrawReqAllowance) + chain2.AssertL2TotalBaseTokens(chain2TotalBaseTokens + baseTokensToWithdrawFromChain1 + withdrawReqAllowance) } From f7083b7cda7c2b1bb8bc723592bf557012352a89 Mon Sep 17 00:00:00 2001 From: Yang Hau Date: Wed, 9 Aug 2023 17:06:29 +0300 Subject: [PATCH 6/6] refactor: Synchronize MinGasFee --- .../wasm/testcore/go/testcoreimpl/funcs.go | 17 ++++---- .../testcore/rs/testcoreimpl/src/funcs.rs | 18 ++++---- contracts/wasm/testcore/schema.yaml | 1 + contracts/wasm/testcore/test/2chains_test.go | 17 +++++--- .../wasm/testcore/ts/testcoreimpl/funcs.ts | 17 ++++---- packages/chain/cons/cons_test.go | 5 +-- packages/solo/ledgerl1l2.go | 3 +- .../testutil/testchain/test_chain_ledger.go | 7 +--- packages/vm/core/accounts/impl.go | 4 +- packages/vm/core/evm/evmimpl/impl.go | 7 ++-- packages/vm/core/evm/evmtest/utils_test.go | 6 +-- .../testcore/custom_onledger_requests_test.go | 12 +++--- .../vm/core/testcore/sbtests/2chains_test.go | 16 ++++--- .../core/testcore/sbtests/check_ctx_test.go | 3 +- .../sbtestsc/impl_withdraw_from_chain.go | 16 +++---- .../testcore/sbtests/sbtestsc/interface.go | 39 +++++++++--------- .../sbtests/sbtestsc/testcore_bg.wasm | Bin 82861 -> 83215 bytes .../vm/core/testcore/sbtests/setup_test.go | 5 +-- packages/vm/gas/table.go | 2 +- .../wasmlib/as/wasmlib/coreaccounts/params.ts | 4 +- packages/wasmvm/wasmlib/as/wasmlib/sandbox.ts | 2 +- .../wasmlib/go/wasmlib/coreaccounts/params.go | 4 +- packages/wasmvm/wasmlib/go/wasmlib/sandbox.go | 3 +- .../wasmlib/interfaces/coreaccounts.yaml | 2 +- .../wasmvm/wasmlib/src/coreaccounts/params.rs | 6 +-- packages/wasmvm/wasmlib/src/sandbox.rs | 2 +- .../wasmlib/ts/wasmlib/coreaccounts/params.ts | 4 +- packages/wasmvm/wasmlib/ts/wasmlib/sandbox.ts | 2 +- 28 files changed, 109 insertions(+), 115 deletions(-) diff --git a/contracts/wasm/testcore/go/testcoreimpl/funcs.go b/contracts/wasm/testcore/go/testcoreimpl/funcs.go index 9f81be144b..6000fa589d 100644 --- a/contracts/wasm/testcore/go/testcoreimpl/funcs.go +++ b/contracts/wasm/testcore/go/testcoreimpl/funcs.go @@ -18,10 +18,10 @@ const ( MsgDoNothing = "========== doing nothing" MsgFailOnPurpose = "failing on purpose" - MsgFullPanic = "========== panic FULL ENTRY POINT =========" + MsgFullPanic = "========== panic FULL ENTRY POINT ==========" MsgJustView = "calling empty view entry point" - MsgViewPanic = "========== panic VIEW =========" + MsgViewPanic = "========== panic VIEW ==========" ) func funcCallOnChain(ctx wasmlib.ScFuncContext, f *CallOnChainContext) { @@ -242,13 +242,10 @@ func funcWithdrawFromChain(ctx wasmlib.ScFuncContext, f *WithdrawFromChainContex transfer := wasmlib.ScTransferFromBalances(ctx.Allowance()) ctx.TransferAllowed(ctx.AccountID(), transfer) - // This is just a test contract, but normally these numbers should - // be parameters because there is no way for the contract to figure - // out the gas fees on the other chain, and it's also silly to run - // the costly calculation to determine storage deposit every time - // unless absolutely necessary. Better to just make sure that the - // storage deposit is large enough, since it will be returned anyway. - const gasFee = wasmlib.MinGasFee + var gasReserveTransferAccountToChain = wasmlib.MinGasFee + if f.Params.GasReserveTransferAccountToChain().Exists() { + gasReserveTransferAccountToChain = f.Params.GasReserveTransferAccountToChain().Value() + } var gasReserve = wasmlib.MinGasFee if f.Params.GasReserve().Exists() { gasReserve = f.Params.GasReserve().Value() @@ -261,7 +258,7 @@ func funcWithdrawFromChain(ctx wasmlib.ScFuncContext, f *WithdrawFromChainContex // NOTE: make sure you READ THE DOCS before calling this function xfer := coreaccounts.ScFuncs.TransferAccountToChain(ctx) xfer.Params.GasReserve().SetValue(gasReserve) - xfer.Func.TransferBaseTokens(storageDeposit + gasFee + gasReserve). + xfer.Func.TransferBaseTokens(storageDeposit + gasReserveTransferAccountToChain + gasReserve). AllowanceBaseTokens(withdrawal + storageDeposit + gasReserve). PostToChain(targetChain) } diff --git a/contracts/wasm/testcore/rs/testcoreimpl/src/funcs.rs b/contracts/wasm/testcore/rs/testcoreimpl/src/funcs.rs index d423b9cc51..6b97d7de56 100644 --- a/contracts/wasm/testcore/rs/testcoreimpl/src/funcs.rs +++ b/contracts/wasm/testcore/rs/testcoreimpl/src/funcs.rs @@ -8,8 +8,8 @@ use crate::*; const CONTRACT_NAME_DEPLOYED: &str = "exampleDeployTR"; const MSG_CORE_ONLY_PANIC: &str = "========== core only ========="; -const MSG_FULL_PANIC: &str = "========== panic FULL ENTRY POINT ========="; -const MSG_VIEW_PANIC: &str = "========== panic VIEW ========="; +const MSG_FULL_PANIC: &str = "========== panic FULL ENTRY POINT =========="; +const MSG_VIEW_PANIC: &str = "========== panic VIEW =========="; pub fn func_call_on_chain(ctx: &ScFuncContext, f: &CallOnChainContext) { let param_int = f.params.n().value(); @@ -255,13 +255,11 @@ pub fn func_withdraw_from_chain(ctx: &ScFuncContext, f: &WithdrawFromChainContex let transfer = ScTransfer::from_balances(&ctx.allowance()); ctx.transfer_allowed(&ctx.account_id(), &transfer); - // This is just a test contract, but normally these numbers should - // be parameters because there is no way for the contract to figure - // out the gas fees on the other chain, and it's also silly to run - // the costly calculation to determine storage deposit every time - // unless absolutely necessary. Better to just make sure that the - // storage deposit is large enough, since it will be returned anyway. - let gas_fee: u64 = MIN_GAS_FEE; + let mut gas_reserve_transfer_account_to_chain: u64 = MIN_GAS_FEE; + if f.params.gas_reserve_transfer_account_to_chain().exists() { + gas_reserve_transfer_account_to_chain = + f.params.gas_reserve_transfer_account_to_chain().value(); + } let mut gas_reserve: u64 = MIN_GAS_FEE; if f.params.gas_reserve().exists() { gas_reserve = f.params.gas_reserve().value(); @@ -275,7 +273,7 @@ pub fn func_withdraw_from_chain(ctx: &ScFuncContext, f: &WithdrawFromChainContex let xfer = coreaccounts::ScFuncs::transfer_account_to_chain(ctx); xfer.params.gas_reserve().set_value(gas_reserve); xfer.func - .transfer_base_tokens(storage_deposit + gas_fee + gas_reserve) + .transfer_base_tokens(storage_deposit + gas_reserve_transfer_account_to_chain + gas_reserve) .allowance_base_tokens(withdrawal + storage_deposit + gas_reserve) .post_to_chain(target_chain); } diff --git a/contracts/wasm/testcore/schema.yaml b/contracts/wasm/testcore/schema.yaml index 005900148b..3b773dbe96 100644 --- a/contracts/wasm/testcore/schema.yaml +++ b/contracts/wasm/testcore/schema.yaml @@ -94,6 +94,7 @@ funcs: chainID: ChainID baseTokens: Uint64 gasReserve: Uint64? + gasReserveTransferAccountToChain: Uint64? views: checkContextFromViewEP: diff --git a/contracts/wasm/testcore/test/2chains_test.go b/contracts/wasm/testcore/test/2chains_test.go index f371a40203..31e836aaa1 100644 --- a/contracts/wasm/testcore/test/2chains_test.go +++ b/contracts/wasm/testcore/test/2chains_test.go @@ -125,11 +125,16 @@ func Test2Chains(t *testing.T) { // allowance for accounts.transferAccountToChain(): SD + GAS1 + GAS2 xferDeposit := wasmlib.StorageDeposit - xferAllowance := xferDeposit + wasmlib.MinGasFee + wasmlib.MinGasFee + const gasFeeTransferAccountToChain = 10 * wasmlib.MinGasFee + const gasReserve = 10 * wasmlib.MinGasFee + const gasWithdrawFromChain = 10 * wasmlib.MinGasFee + xferAllowance := xferDeposit + gasReserve + gasFeeTransferAccountToChain f := testcore.ScFuncs.WithdrawFromChain(ctx2.Sign(user)) f.Params.ChainID().SetValue(ctx1.CurrentChainID()) f.Params.BaseTokens().SetValue(withdrawalAmount) - f.Func.TransferBaseTokens(xferAllowance + isc.Million). + f.Params.GasReserve().SetValue(gasReserve) + f.Params.GasReserveTransferAccountToChain().SetValue(gasFeeTransferAccountToChain) + f.Func.TransferBaseTokens(xferAllowance + gasWithdrawFromChain). AllowanceBaseTokens(xferAllowance).Post() require.NoError(t, ctx2.Err) @@ -153,21 +158,21 @@ func Test2Chains(t *testing.T) { // chain2.testcore account will be credited with SD+GAS1+GAS2, pay actual GAS1, // and be debited by SD+GAS2+'withdrawalAmount' bal1.UpdateFeeBalances(ctxAcc1.GasFee) - bal1.Add(testcore2, xferDeposit+wasmlib.MinGasFee+wasmlib.MinGasFee-ctxAcc1.GasFee-xferDeposit-wasmlib.MinGasFee-withdrawalAmount) + bal1.Add(testcore2, xferDeposit+gasWithdrawFromChain+gasWithdrawFromChain-ctxAcc1.GasFee-xferDeposit-gasReserve-withdrawalAmount) // verify these changes against the actual chain1 account balances bal1.VerifyBalances(t) - userL1 -= xferAllowance + isc.Million + userL1 -= xferAllowance + gasWithdrawFromChain require.Equal(t, userL1, user.Balance()) // The gas fees will be credited to chain1.Originator bal2.UpdateFeeBalances(withdrawalReceipt.GasFeeCharged) bal2.UpdateFeeBalances(transferReceipt.GasFeeCharged) // deduct coretest.WithdrawFromChain() gas fee from user's cool million - bal2.Add(user, isc.Million-withdrawalReceipt.GasFeeCharged) + bal2.Add(user, gasWithdrawFromChain-withdrawalReceipt.GasFeeCharged) // chain2.accounts1 will be credited with SD+GAS2+'withdrawalAmount', pay actual GAS2, // and be debited by SD+'withdrawalAmount', leaving zero - bal2.Add(accounts1, xferDeposit+wasmlib.MinGasFee+withdrawalAmount-transferReceipt.GasFeeCharged-xferDeposit-withdrawalAmount) + bal2.Add(accounts1, xferDeposit+gasReserve+withdrawalAmount-transferReceipt.GasFeeCharged-xferDeposit-withdrawalAmount) // chain2.testcore account receives the withdrawn tokens and storage deposit bal2.Account += withdrawalAmount + xferDeposit // verify these changes against the actual chain2 account balances diff --git a/contracts/wasm/testcore/ts/testcoreimpl/funcs.ts b/contracts/wasm/testcore/ts/testcoreimpl/funcs.ts index 756c0f04c0..6d65a9419f 100644 --- a/contracts/wasm/testcore/ts/testcoreimpl/funcs.ts +++ b/contracts/wasm/testcore/ts/testcoreimpl/funcs.ts @@ -9,8 +9,8 @@ import * as sc from "../testcore/index"; const CONTRACT_NAME_DEPLOYED = "exampleDeployTR"; const MSG_CORE_ONLY_PANIC = "========== core only ========="; -const MSG_FULL_PANIC = "========== panic FULL ENTRY POINT ========="; -const MSG_VIEW_PANIC = "========== panic VIEW ========="; +const MSG_FULL_PANIC = "========== panic FULL ENTRY POINT =========="; +const MSG_VIEW_PANIC = "========== panic VIEW =========="; export function funcCallOnChain(ctx: wasmlib.ScFuncContext, f: sc.CallOnChainContext): void { let paramInt = f.params.n().value(); @@ -228,13 +228,10 @@ export function funcWithdrawFromChain(ctx: wasmlib.ScFuncContext, f: sc.Withdraw const transfer = wasmlib.ScTransfer.fromBalances(ctx.allowance()); ctx.transferAllowed(ctx.accountID(), transfer); - // This is just a test contract, but normally these numbers should - // be parameters because there is no way for the contract to figure - // out the gas fees on the other chain, and it's also silly to run - // the costly calculation to determine storage deposit every time - // unless absolutely necessary. Better to just make sure that the - // storage deposit is large enough, since it will be returned anyway. - const gasFee: u64 = wasmlib.MinGasFee; + let gasReserveTransferAccountToChain: u64 = wasmlib.MinGasFee; + if (f.params.gasReserveTransferAccountToChain().exists()) { + gasReserveTransferAccountToChain = f.params.gasReserveTransferAccountToChain().value(); + } let gasReserve: u64 = wasmlib.MinGasFee; if (f.params.gasReserve().exists()) { gasReserve = f.params.gasReserve().value(); @@ -247,7 +244,7 @@ export function funcWithdrawFromChain(ctx: wasmlib.ScFuncContext, f: sc.Withdraw // NOTE: make sure you READ THE DOCS before calling this function const xfer = coreaccounts.ScFuncs.transferAccountToChain(ctx); xfer.params.gasReserve().setValue(gasReserve); - xfer.func.transferBaseTokens(storageDeposit + gasFee + gasReserve) + xfer.func.transferBaseTokens(storageDeposit + gasReserveTransferAccountToChain + gasReserve) .allowanceBaseTokens(withdrawal + storageDeposit + gasReserve) .postToChain(targetChain); } diff --git a/packages/chain/cons/cons_test.go b/packages/chain/cons/cons_test.go index 487ae531e3..abd67e3327 100644 --- a/packages/chain/cons/cons_test.go +++ b/packages/chain/cons/cons_test.go @@ -34,9 +34,9 @@ import ( "github.com/iotaledger/wasp/packages/vm/core/accounts" "github.com/iotaledger/wasp/packages/vm/core/coreprocessors" "github.com/iotaledger/wasp/packages/vm/core/migrations/allmigrations" + "github.com/iotaledger/wasp/packages/vm/gas" "github.com/iotaledger/wasp/packages/vm/processors" "github.com/iotaledger/wasp/packages/vm/vmimpl" - "github.com/iotaledger/wasp/packages/wasmvm/wasmlib/go/wasmlib" ) // Here we run a single consensus instance, step by step with @@ -347,8 +347,7 @@ func testChained(t *testing.T, n, f, b int) { inccounter.FuncIncCounter.Hname(), dict.New(), uint64(i*reqPerBlock+ii), - // FIXME may user other MinGasFee instead of wasmlib.MinGasFee - wasmlib.MinGasFee, + gas.LimitsDefault.MinGasPerRequest, ).Sign(scClient) reqs = append(reqs, scRequest) incTotal++ diff --git a/packages/solo/ledgerl1l2.go b/packages/solo/ledgerl1l2.go index f5e2e14457..e8c994f8e8 100644 --- a/packages/solo/ledgerl1l2.go +++ b/packages/solo/ledgerl1l2.go @@ -203,7 +203,8 @@ func (fp *foundryParams) CreateFoundry() (uint32, iotago.NativeTokenID, error) { user = fp.user } req := CallParamsFromDict(accounts.Contract.Name, accounts.FuncFoundryCreateNew.Name, par). - WithAllowance(isc.NewAssetsBaseTokens(allowanceForFoundryStorageDeposit)) + WithAllowance(isc.NewAssetsBaseTokens(allowanceForFoundryStorageDeposit)). + AddBaseTokens(allowanceForFoundryStorageDeposit) gas, _, err := fp.ch.EstimateGasOnLedger(req, user, true) if err != nil { diff --git a/packages/testutil/testchain/test_chain_ledger.go b/packages/testutil/testchain/test_chain_ledger.go index 142e45a27b..70d3561c04 100644 --- a/packages/testutil/testchain/test_chain_ledger.go +++ b/packages/testutil/testchain/test_chain_ledger.go @@ -21,7 +21,6 @@ import ( "github.com/iotaledger/wasp/packages/vm/core/migrations/allmigrations" "github.com/iotaledger/wasp/packages/vm/core/root" "github.com/iotaledger/wasp/packages/vm/gas" - "github.com/iotaledger/wasp/packages/wasmvm/wasmlib/go/wasmlib" ) //////////////////////////////////////////////////////////////////////////////// @@ -87,8 +86,7 @@ func (tcl *TestChainLedger) MakeTxAccountsDeposit(account *cryptolib.KeyPair) [] Metadata: &isc.SendMetadata{ TargetContract: accounts.Contract.Hname(), EntryPoint: accounts.FuncDeposit.Hname(), - // FIXME may user other MinGasFee instead of wasmlib.MinGasFee - GasBudget: wasmlib.MinGasFee, + GasBudget: 2 * gas.LimitsDefault.MinGasPerRequest, }, }, }, @@ -119,8 +117,7 @@ func (tcl *TestChainLedger) MakeTxDeployIncCounterContract() []isc.Request { root.ParamName: inccounter.Contract.Name, inccounter.VarCounter: 0, }), - // FIXME may user other MinGasFee instead of wasmlib.MinGasFee - GasBudget: wasmlib.MinGasFee, + GasBudget: 2 * gas.LimitsDefault.MinGasPerRequest, }, }, }, diff --git a/packages/vm/core/accounts/impl.go b/packages/vm/core/accounts/impl.go index 881c9a996d..a513dd8781 100644 --- a/packages/vm/core/accounts/impl.go +++ b/packages/vm/core/accounts/impl.go @@ -11,7 +11,7 @@ import ( "github.com/iotaledger/wasp/packages/util" "github.com/iotaledger/wasp/packages/vm" "github.com/iotaledger/wasp/packages/vm/core/errors/coreerrors" - "github.com/iotaledger/wasp/packages/wasmvm/wasmlib/go/wasmlib" + "github.com/iotaledger/wasp/packages/vm/gas" ) func CommonAccount() isc.AgentID { @@ -176,7 +176,7 @@ func transferAccountToChain(ctx isc.Sandbox) dict.Dict { assets := allowance.Clone() // deduct the gas reserve GAS2 from the allowance, if possible - gasReserve := ctx.Params().MustGetUint64(ParamGasReserve, wasmlib.MinGasFee) + gasReserve := ctx.Params().MustGetUint64(ParamGasReserve, gas.LimitsDefault.MinGasPerRequest) if allowance.BaseTokens < gasReserve { panic(ErrNotEnoughAllowance) } diff --git a/packages/vm/core/evm/evmimpl/impl.go b/packages/vm/core/evm/evmimpl/impl.go index 4e3883b967..8b819b9537 100644 --- a/packages/vm/core/evm/evmimpl/impl.go +++ b/packages/vm/core/evm/evmimpl/impl.go @@ -29,7 +29,6 @@ import ( "github.com/iotaledger/wasp/packages/vm/core/evm/iscmagic" "github.com/iotaledger/wasp/packages/vm/core/governance" "github.com/iotaledger/wasp/packages/vm/gas" - "github.com/iotaledger/wasp/packages/wasmvm/wasmlib/go/wasmlib" ) var Processor = evm.Contract.Processor(nil, @@ -254,14 +253,14 @@ func registerERC20NativeTokenOnRemoteChain(ctx isc.Sandbox) dict.Dict { evm.FieldFoundryTokenScheme: codec.EncodeTokenScheme(tokenScheme), }, // FIXME why does this gas budget is higher than the allowance below - GasBudget: 5 * wasmlib.MinGasFee, + GasBudget: 50 * gas.LimitsDefault.MinGasPerRequest, }, } sd := ctx.EstimateRequiredStorageDeposit(req) // this request is sent by contract account, // so we move enough allowance for the gas fee below in the req.Assets.AddBaseTokens() function call - ctx.TransferAllowedFunds(ctx.AccountID(), isc.NewAssetsBaseTokens(sd+wasmlib.MinGasFee)) - req.Assets.AddBaseTokens(sd + wasmlib.MinGasFee) + ctx.TransferAllowedFunds(ctx.AccountID(), isc.NewAssetsBaseTokens(sd+10*gas.LimitsDefault.MinGasPerRequest)) + req.Assets.AddBaseTokens(sd + 10*gas.LimitsDefault.MinGasPerRequest) ctx.Send(req) return nil diff --git a/packages/vm/core/evm/evmtest/utils_test.go b/packages/vm/core/evm/evmtest/utils_test.go index 465a2ce0a3..8e56456e7a 100644 --- a/packages/vm/core/evm/evmtest/utils_test.go +++ b/packages/vm/core/evm/evmtest/utils_test.go @@ -33,7 +33,6 @@ import ( "github.com/iotaledger/wasp/packages/vm/core/evm/iscmagic" "github.com/iotaledger/wasp/packages/vm/core/governance" "github.com/iotaledger/wasp/packages/vm/gas" - "github.com/iotaledger/wasp/packages/wasmvm/wasmlib/go/wasmlib" ) type soloChainEnv struct { @@ -373,9 +372,8 @@ func (e *soloChainEnv) registerERC20ExternalNativeToken( evm.FieldTargetAddress: codec.EncodeAddress(e.soloChain.ChainID.AsAddress()), }). // to cover sd and gas fee for the 'FuncRegisterERC20ExternalNativeToken' func call in 'FuncRegisterERC20NativeTokenOnRemoteChain' - WithAllowance(isc.NewAssetsBaseTokens(2*wasmlib.MinGasFee)). - // FIXME why this gas budget is less than the gas budget of the indirect call FuncRegisterERC20ExternalNativeToken - WithGasBudget(wasmlib.MinGasFee), + WithAllowance(isc.NewAssetsBaseTokens(20*gas.LimitsDefault.MinGasPerRequest)). + WithGasBudget(10*gas.LimitsDefault.MinGasPerRequest), fromChain.OriginatorPrivateKey) if err != nil { return ret, err diff --git a/packages/vm/core/testcore/custom_onledger_requests_test.go b/packages/vm/core/testcore/custom_onledger_requests_test.go index be269ada30..dd2e71ecda 100644 --- a/packages/vm/core/testcore/custom_onledger_requests_test.go +++ b/packages/vm/core/testcore/custom_onledger_requests_test.go @@ -16,7 +16,7 @@ import ( "github.com/iotaledger/wasp/packages/testutil/testmisc" "github.com/iotaledger/wasp/packages/transaction" "github.com/iotaledger/wasp/packages/vm/core/accounts" - "github.com/iotaledger/wasp/packages/wasmvm/wasmlib/go/wasmlib" + "github.com/iotaledger/wasp/packages/vm/gas" ) func TestNoSenderFeature(t *testing.T) { @@ -28,7 +28,9 @@ func TestNoSenderFeature(t *testing.T) { // ---------------------------------------------------------------- // mint some NTs and withdraw them - err := ch.DepositAssetsToL2(isc.NewAssetsBaseTokens(10*isc.Million), wallet) + gasFee := 10 * gas.LimitsDefault.MinGasPerRequest + withdrawAmount := 3 * gas.LimitsDefault.MinGasPerRequest + err := ch.DepositAssetsToL2(isc.NewAssetsBaseTokens(withdrawAmount+gasFee), wallet) require.NoError(t, err) nativeTokenAmount := big.NewInt(123) sn, nativeTokenID, err := ch.NewFoundryParams(1234). @@ -40,8 +42,8 @@ func TestNoSenderFeature(t *testing.T) { require.NoError(t, err) // withdraw native tokens to L1 - allowance := 5 * isc.Million - baseTokensToSend := allowance + wasmlib.MinGasFee + allowance := withdrawAmount + baseTokensToSend := allowance + gasFee _, err = ch.PostRequestOffLedger(solo.NewCallParams( accounts.Contract.Name, accounts.FuncWithdraw.Name, ). @@ -51,7 +53,7 @@ func TestNoSenderFeature(t *testing.T) { ID: nativeTokenID, Amount: nativeTokenAmount, }). - WithGasBudget(wasmlib.MinGasFee), + WithGasBudget(gasFee), wallet) require.NoError(t, err) diff --git a/packages/vm/core/testcore/sbtests/2chains_test.go b/packages/vm/core/testcore/sbtests/2chains_test.go index 1b0a0e960d..943aed5205 100644 --- a/packages/vm/core/testcore/sbtests/2chains_test.go +++ b/packages/vm/core/testcore/sbtests/2chains_test.go @@ -13,6 +13,7 @@ import ( "github.com/iotaledger/wasp/packages/vm/core/accounts" "github.com/iotaledger/wasp/packages/vm/core/corecontracts" "github.com/iotaledger/wasp/packages/vm/core/testcore/sbtests/sbtestsc" + "github.com/iotaledger/wasp/packages/vm/gas" "github.com/iotaledger/wasp/packages/wasmvm/wasmlib/go/wasmlib" ) @@ -64,7 +65,7 @@ func test2Chains(t *testing.T, w bool) { // send base tokens to contractAgentID2 (that is an entity of chain2) on chain1 const baseTokensCreditedToScOnChain1 = 10 * isc.Million - const creditBaseTokensToSend = baseTokensCreditedToScOnChain1 + wasmlib.MinGasFee + creditBaseTokensToSend := baseTokensCreditedToScOnChain1 + gas.LimitsDefault.MinGasPerRequest _, err = chain1.PostRequestSync(solo.NewCallParams( accounts.Contract.Name, accounts.FuncTransferAllowanceTo.Name, accounts.ParamAgentID, contractAgentID2, @@ -97,10 +98,10 @@ func test2Chains(t *testing.T, w bool) { // make chain2 send a call to chain1 to withdraw base tokens baseTokensToWithdrawFromChain1 := baseTokensCreditedToScOnChain1 - const gasFee1 = wasmlib.MinGasFee + gasFeeTransferAccountToChain := 10 * gas.LimitsDefault.MinGasPerRequest // gas reserve for the 'TransferAllowanceTo' func call in 'TransferAccountToChain' func call - const gasReserve = wasmlib.MinGasFee - const withdrawFeeGas = wasmlib.MinGasFee + gasReserve := 10 * gas.LimitsDefault.MinGasPerRequest + withdrawFeeGas := 10 * gas.LimitsDefault.MinGasPerRequest const storageDeposit = wasmlib.StorageDeposit // NOTE: make sure you READ THE DOCS for accounts.transferAccountToChain() @@ -111,7 +112,7 @@ func test2Chains(t *testing.T, w bool) { // the gas fees for the chain2.accounts.transferAccountToChain() request and the // chain1.accounts.transferAllowanceTo() request. // note that the storage deposit will be returned in the end - withdrawReqAllowance := storageDeposit + gasFee1 + gasReserve + withdrawReqAllowance := storageDeposit + gasFeeTransferAccountToChain + gasReserve // also cover gas fee for `FuncWithdrawFromChain` on chain2 withdrawBaseTokensToSend := withdrawReqAllowance + withdrawFeeGas @@ -121,6 +122,7 @@ func test2Chains(t *testing.T, w bool) { sbtestsc.ParamChainID, chain1.ChainID, sbtestsc.ParamBaseTokens, baseTokensToWithdrawFromChain1, sbtestsc.ParamGasReserve, gasReserve, + sbtestsc.ParamGasReserveTransferAccountToChain, gasFeeTransferAccountToChain, ). AddBaseTokens(withdrawBaseTokensToSend). WithAllowance(isc.NewAssetsBaseTokens(withdrawReqAllowance)). @@ -165,9 +167,11 @@ func test2Chains(t *testing.T, w bool) { env.AssertL1BaseTokens(userAddress, utxodb.FundsFromFaucetAmount-creditBaseTokensToSend-withdrawBaseTokensToSend) // on chain1 user only made the first transaction, so it is the same as its balance before 'WithdrawFromChain' function call chain1.AssertL2BaseTokens(userAgentID, creditBaseTokensToSend-baseTokensCreditedToScOnChain1-chain1TransferAllowanceGas) + // gasFeeTransferAccountToChain is is used for paying the gas fee of the 'TransferAccountToChain' func call + // in 'WithdrawFromChain' func call // gasReserve is used for paying the gas fee of the 'TransferAllowanceTo' func call in 'TransferAccountToChain' func call // So the token left in contractAgentID2 on chain1 is the unused gas fee - chain1.AssertL2BaseTokens(contractAgentID2, gasReserve-chain1TransferAccountToChainGas) + chain1.AssertL2BaseTokens(contractAgentID2, gasFeeTransferAccountToChain-chain1TransferAccountToChainGas) // tokens in 'withdrawBaseTokensToSend' amount are moved with the request from L1 to L2 // 'withdrawReqAllowance' is is the amount moved from chain1 to chain2 with the request // 'baseTokensToWithdrawFromChain1' is the amount we assigned to withdraw in 'WithdrawFromChain' func call diff --git a/packages/vm/core/testcore/sbtests/check_ctx_test.go b/packages/vm/core/testcore/sbtests/check_ctx_test.go index ee622afb87..125c2f2718 100644 --- a/packages/vm/core/testcore/sbtests/check_ctx_test.go +++ b/packages/vm/core/testcore/sbtests/check_ctx_test.go @@ -8,6 +8,7 @@ import ( "github.com/iotaledger/wasp/packages/isc" "github.com/iotaledger/wasp/packages/solo" "github.com/iotaledger/wasp/packages/vm/core/testcore/sbtests/sbtestsc" + "github.com/iotaledger/wasp/packages/vm/gas" ) func TestMainCallsFromFullEP(t *testing.T) { run2(t, testMainCallsFromFullEP) } @@ -24,7 +25,7 @@ func testMainCallsFromFullEP(t *testing.T, w bool) { sbtestsc.ParamCaller, userAgentID, sbtestsc.ParamChainOwnerID, chain.OriginatorAgentID, ). - WithGasBudget(120_000) + WithGasBudget(10 * gas.LimitsDefault.MinGasPerRequest) _, err := chain.PostRequestSync(req, user) require.NoError(t, err) } diff --git a/packages/vm/core/testcore/sbtests/sbtestsc/impl_withdraw_from_chain.go b/packages/vm/core/testcore/sbtests/sbtestsc/impl_withdraw_from_chain.go index 35197990a4..f0410708d0 100644 --- a/packages/vm/core/testcore/sbtests/sbtestsc/impl_withdraw_from_chain.go +++ b/packages/vm/core/testcore/sbtests/sbtestsc/impl_withdraw_from_chain.go @@ -5,6 +5,7 @@ import ( "github.com/iotaledger/wasp/packages/kv/codec" "github.com/iotaledger/wasp/packages/kv/dict" "github.com/iotaledger/wasp/packages/vm/core/accounts" + "github.com/iotaledger/wasp/packages/vm/gas" "github.com/iotaledger/wasp/packages/wasmvm/wasmlib/go/wasmlib" ) @@ -21,23 +22,16 @@ func withdrawFromChain(ctx isc.Sandbox) dict.Dict { // plus gas fees for the outgoing request to accounts.transferAllowanceTo() ctx.TransferAllowedFunds(ctx.AccountID()) - // This is just a test contract, but normally these numbers should - // be parameters because there is no way for the contract to figure - // out the gas fees on the other chain, and it's also silly to run - // the costly calculation to determine storage deposit every time - // unless absolutely necessary. Better to just make sure that the - // storage deposit is large enough, since it will be returned anyway. - // gasFee is for sending FuncTransferAccountToChain() request - const gasFee = wasmlib.MinGasFee - // gasReserve is the gas fee for the function all inside FuncTransferAccountToChain() - gasReserve := params.MustGetUint64(ParamGasReserve, wasmlib.MinGasFee) + // gasReserve is the gas fee for the 'TransferAllowanceTo' function call ub 'TransferAccountToChain' + gasReserve := params.MustGetUint64(ParamGasReserve, gas.LimitsDefault.MinGasPerRequest) + gasReserveTransferAccountToChain := params.MustGetUint64(ParamGasReserveTransferAccountToChain, gas.LimitsDefault.MinGasPerRequest) const storageDeposit = wasmlib.StorageDeposit // make sure to send enough to cover the storage deposit and gas fees // the storage deposit will be returned along with the withdrawal ctx.Send(isc.RequestParameters{ TargetAddress: targetChain.AsAddress(), - Assets: isc.NewAssetsBaseTokens(storageDeposit + gasFee + gasReserve), + Assets: isc.NewAssetsBaseTokens(storageDeposit + gasReserveTransferAccountToChain + gasReserve), Metadata: &isc.SendMetadata{ TargetContract: accounts.Contract.Hname(), EntryPoint: accounts.FuncTransferAccountToChain.Hname(), diff --git a/packages/vm/core/testcore/sbtests/sbtestsc/interface.go b/packages/vm/core/testcore/sbtests/sbtestsc/interface.go index 6c3746043b..7d959f0baa 100644 --- a/packages/vm/core/testcore/sbtests/sbtestsc/interface.go +++ b/packages/vm/core/testcore/sbtests/sbtestsc/interface.go @@ -116,25 +116,26 @@ const ( VarContractNameDeployed = "exampleDeployTR" // parameters - ParamAddress = "address" - ParamAgentID = "agentID" - ParamCaller = "caller" - ParamChainID = "chainID" - ParamChainOwnerID = "chainOwnerID" - ParamGasReserve = "gasReserve" - ParamContractID = "contractID" - ParamFail = "initFailParam" - ParamHnameContract = "hnameContract" - ParamHnameEP = "hnameEP" - ParamIntParamName = "intParamName" - ParamIntParamValue = "intParamValue" - ParamBaseTokens = "baseTokens" - ParamN = "n" - ParamProgHash = "progHash" - ParamSize = "size" + ParamAddress = "address" + ParamAgentID = "agentID" + ParamCaller = "caller" + ParamChainID = "chainID" + ParamChainOwnerID = "chainOwnerID" + ParamGasReserve = "gasReserve" + ParamGasReserveTransferAccountToChain = "gasReserveTransferAccountToChain" + ParamContractID = "contractID" + ParamFail = "initFailParam" + ParamHnameContract = "hnameContract" + ParamHnameEP = "hnameEP" + ParamIntParamName = "intParamName" + ParamIntParamValue = "intParamValue" + ParamBaseTokens = "baseTokens" + ParamN = "n" + ParamProgHash = "progHash" + ParamSize = "size" // error fragments for testing - MsgDoNothing = "========== doing nothing" - MsgFullPanic = "========== panic FULL ENTRY POINT =========" - MsgViewPanic = "========== panic VIEW =========" + MsgDoNothing = "========== doing nothing ==========" + MsgFullPanic = "========== panic FULL ENTRY POINT ==========" + MsgViewPanic = "========== panic VIEW ==========" ) diff --git a/packages/vm/core/testcore/sbtests/sbtestsc/testcore_bg.wasm b/packages/vm/core/testcore/sbtests/sbtestsc/testcore_bg.wasm index 78e587668137baae9031a79200f8a00156797ad2..7f7bb015ad21223c322c8d8568553f4879831c25 100644 GIT binary patch literal 83215 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 ScImmutableUint64 { ScImmutableUint64::new(self.proxy.root(PARAM_GAS_RESERVE)) } @@ -145,7 +145,7 @@ pub struct MutableTransferAccountToChainParams { impl MutableTransferAccountToChainParams { // Optional gas amount to reserve in the allowance for the internal - // call to transferAllowanceTo(). Default 100_000 (MinGasFee). + // call to transferAllowanceTo(). Default 10_000 (MinGasFee). pub fn gas_reserve(&self) -> ScMutableUint64 { ScMutableUint64::new(self.proxy.root(PARAM_GAS_RESERVE)) } diff --git a/packages/wasmvm/wasmlib/src/sandbox.rs b/packages/wasmvm/wasmlib/src/sandbox.rs index de92880bbf..1f278b32d0 100644 --- a/packages/wasmvm/wasmlib/src/sandbox.rs +++ b/packages/wasmvm/wasmlib/src/sandbox.rs @@ -8,7 +8,7 @@ use crate::host::*; use crate::wasmrequests::*; // @formatter:off -pub const MIN_GAS_FEE : u64 = 100_000; +pub const MIN_GAS_FEE : u64 = 10_000; pub const STORAGE_DEPOSIT : u64 = 20_000; pub const FN_ACCOUNT_ID : i32 = -1; diff --git a/packages/wasmvm/wasmlib/ts/wasmlib/coreaccounts/params.ts b/packages/wasmvm/wasmlib/ts/wasmlib/coreaccounts/params.ts index cfe8d654c9..374ca3414b 100644 --- a/packages/wasmvm/wasmlib/ts/wasmlib/coreaccounts/params.ts +++ b/packages/wasmvm/wasmlib/ts/wasmlib/coreaccounts/params.ts @@ -70,7 +70,7 @@ export class MutableFoundryModifySupplyParams extends wasmtypes.ScProxy { export class ImmutableTransferAccountToChainParams extends wasmtypes.ScProxy { // Optional gas amount to reserve in the allowance for the internal - // call to transferAllowanceTo(). Default 100_000 (MinGasFee). + // call to transferAllowanceTo(). Default 10_000 (MinGasFee). gasReserve(): wasmtypes.ScImmutableUint64 { return new wasmtypes.ScImmutableUint64(this.proxy.root(sc.ParamGasReserve)); } @@ -78,7 +78,7 @@ export class ImmutableTransferAccountToChainParams extends wasmtypes.ScProxy { export class MutableTransferAccountToChainParams extends wasmtypes.ScProxy { // Optional gas amount to reserve in the allowance for the internal - // call to transferAllowanceTo(). Default 100_000 (MinGasFee). + // call to transferAllowanceTo(). Default 10_000 (MinGasFee). gasReserve(): wasmtypes.ScMutableUint64 { return new wasmtypes.ScMutableUint64(this.proxy.root(sc.ParamGasReserve)); } diff --git a/packages/wasmvm/wasmlib/ts/wasmlib/sandbox.ts b/packages/wasmvm/wasmlib/ts/wasmlib/sandbox.ts index 8edcf89e3e..f4c315be72 100644 --- a/packages/wasmvm/wasmlib/ts/wasmlib/sandbox.ts +++ b/packages/wasmvm/wasmlib/ts/wasmlib/sandbox.ts @@ -2,7 +2,7 @@ // SPDX-License-Identifier: Apache-2.0 // @formatter:off -export const MinGasFee : u64 = 100_000n; +export const MinGasFee : u64 = 10_000n; export const StorageDeposit : u64 = 20_000n; export const FnAccountID : i32 = -1;