From 8e87bf45662eba71659f875a3ee0c78800e3e2ab Mon Sep 17 00:00:00 2001 From: sgladkov Date: Fri, 4 Nov 2022 15:32:29 +0300 Subject: [PATCH 01/16] Adjust gas consumption for external handlers --- .../Blockchain/VM/ExternalHandler.cs | 27 +++++++++++++---- src/Lachain.Core/Blockchain/VM/GasMetering.cs | 30 ++++++++++++------- 2 files changed, 41 insertions(+), 16 deletions(-) diff --git a/src/Lachain.Core/Blockchain/VM/ExternalHandler.cs b/src/Lachain.Core/Blockchain/VM/ExternalHandler.cs index b0a53dbac..e39b6f405 100644 --- a/src/Lachain.Core/Blockchain/VM/ExternalHandler.cs +++ b/src/Lachain.Core/Blockchain/VM/ExternalHandler.cs @@ -257,6 +257,7 @@ public static void Handler_Env_CopyCallValue(int from, int to, int offset) ?? throw new InvalidOperationException("Cannot call COPYCALLVALUE outside wasm frame"); if (from < 0 || to > frame.Input.Length || from > to) throw new InvalidContractException("Copy to contract memory failed: bad range"); + frame.UseGas(GasMetering.CopyCodeValueGasCost); if (!SafeCopyToMemory(frame.Memory, frame.Input.Skip(from).Take(to - from).ToArray(), offset)) throw new InvalidContractException("Copy to contract memory failed"); } @@ -327,6 +328,7 @@ int topic3Offset }, topics ); + frame.UseGas(GasMetering.WriteEventPerByteGas * ((ulong)data.Length + 1000UL)); frame.InvocationContext.Snapshot.Events.AddEvent(eventObj); } @@ -1058,6 +1060,7 @@ public static void Handler_Env_SetReturn(int offset, int length) Logger.LogInformation($"Handler_Env_SetReturn({offset}, {length})"); var frame = VirtualMachine.ExecutionFrames.Peek() as WasmExecutionFrame ?? throw new InvalidOperationException("Cannot call SETRETURN outside wasm frame"); + frame.UseGas(GasMetering.SetReturnGasCost); var ret = SafeCopyFromMemory(frame.Memory, offset, length); Logger.LogInformation($"ret: {ret.ToHex()}"); if (ret is null) @@ -1072,6 +1075,7 @@ public static void Handler_Env_GetSender(int dataOffset) ?? throw new InvalidOperationException("Cannot call GETSENDER outside wasm frame"); var data = (frame.InvocationContext.Message?.Sender ?? frame.InvocationContext.Sender).ToBytes(); Logger.LogInformation($"Data: {data.ToHex()}"); + frame.UseGas(GasMetering.GetSimpleDataGasCost); var ret = SafeCopyToMemory(frame.Memory, data, dataOffset); if (!ret) throw new InvalidContractException("Bad call to GETSENDER"); @@ -1082,6 +1086,7 @@ public static void Handler_Env_GetGasLeft(int dataOffset) Logger.LogInformation($"Handler_Env_GetGasLeft({dataOffset})"); var frame = VirtualMachine.ExecutionFrames.Peek() as WasmExecutionFrame ?? throw new InvalidOperationException("Cannot call GETGASLEFT outside wasm frame"); + frame.UseGas(GasMetering.GetGasLeftGasCost); var data = (frame.GasLimit - frame.GasUsed).ToBytes().ToArray(); var ret = SafeCopyToMemory(frame.Memory, data, dataOffset); if (!ret) @@ -1093,6 +1098,7 @@ public static void Handler_Env_GetTxOrigin(int dataOffset) Logger.LogInformation($"Handler_Env_GetTxOrigin({dataOffset})"); var frame = VirtualMachine.ExecutionFrames.Peek() as WasmExecutionFrame ?? throw new InvalidOperationException("Cannot call GETTXORIGIN outside wasm frame"); + frame.UseGas(GasMetering.GetSimpleDataGasCost); var data = frame.InvocationContext.Sender.ToBytes(); var ret = SafeCopyToMemory(frame.Memory, data, dataOffset); if (!ret) @@ -1104,6 +1110,7 @@ public static void Handler_Env_GetTxGasPrice(int dataOffset) Logger.LogInformation($"Handler_Env_GetTxGasPrice({dataOffset})"); var frame = VirtualMachine.ExecutionFrames.Peek() as WasmExecutionFrame ?? throw new InvalidOperationException("Cannot call GETTXGASPRICE outside wasm frame"); + frame.UseGas(GasMetering.GetSimpleDataGasCost); var data = frame.InvocationContext.Receipt.Transaction.GasPrice.ToBytes().ToArray(); var ret = SafeCopyToMemory(frame.Memory, data, dataOffset); if (!ret) @@ -1276,6 +1283,7 @@ public static void Handler_Env_GetTransferredFunds(int dataOffset) Logger.LogInformation($"Handler_Env_GetTransferredFunds({dataOffset})"); var frame = VirtualMachine.ExecutionFrames.Peek() as WasmExecutionFrame ?? throw new InvalidOperationException("Cannot call GETCALLVALUE outside wasm frame"); + frame.UseGas(GasMetering.GetSimpleDataGasCost); var data = frame.InvocationContext.Value.ToBytes(); var ret = SafeCopyToMemory(frame.Memory, data, dataOffset); if (!ret) @@ -1287,6 +1295,7 @@ public static void Handler_Env_GetTransactionHash(int dataOffset) Logger.LogInformation($"Handler_Env_GetTransactionHash({dataOffset})"); var frame = VirtualMachine.ExecutionFrames.Peek() as WasmExecutionFrame ?? throw new InvalidOperationException("Cannot call TXHASH outside wasm frame"); + frame.UseGas(GasMetering.GetSimpleDataGasCost); var data = frame.InvocationContext.TransactionHash.ToBytes(); var ret = SafeCopyToMemory(frame.Memory, data, dataOffset); if (!ret) @@ -1322,8 +1331,11 @@ public static void Handler_Env_GetAddress(int resultOffset) Logger.LogInformation($"Handler_Env_GetAddress({resultOffset})"); var frame = VirtualMachine.ExecutionFrames.Peek() as WasmExecutionFrame ?? throw new InvalidOperationException("Cannot call GetAddress outside wasm frame"); + frame.UseGas(GasMetering.GetSimpleDataGasCost); var result = (frame.InvocationContext.Message?.Delegate ?? frame.CurrentAddress).ToBytes(); - SafeCopyToMemory(frame.Memory, result, resultOffset); + var ret = SafeCopyToMemory(frame.Memory, result, resultOffset); + if (!ret) + throw new InvalidContractException("Bad call to (get_address)"); } public static void Handler_Env_GetMsgValue(int dataOffset) @@ -1331,6 +1343,7 @@ public static void Handler_Env_GetMsgValue(int dataOffset) Logger.LogInformation($"Handler_Env_GetMsgValue({dataOffset})"); var frame = VirtualMachine.ExecutionFrames.Peek() as WasmExecutionFrame ?? throw new InvalidOperationException("Cannot call GetMsgValue outside wasm frame"); + frame.UseGas(GasMetering.GetSimpleDataGasCost); var data = (frame.InvocationContext.Message?.Value ?? frame.InvocationContext.Value).ToBytes().Reverse().ToArray(); var ret = SafeCopyToMemory(frame.Memory, data, dataOffset); if (!ret) @@ -1342,8 +1355,8 @@ public static void Handler_Env_GetBlockGasLimit(int dataOffset) Logger.LogInformation($"Handler_Env_GetBlockGasLimit({dataOffset})"); var frame = VirtualMachine.ExecutionFrames.Peek() as WasmExecutionFrame ?? throw new InvalidOperationException("Cannot call GetBlockGasLimit outside wasm frame"); + frame.UseGas(GasMetering.GetSimpleDataGasCost); const ulong defaultBlockGasLimit = GasMetering.DefaultBlockGasLimit; - // Load `default block gasLimit` at given memory offset var ret = SafeCopyToMemory(frame.Memory, defaultBlockGasLimit.ToBytes().ToArray(), dataOffset); if (!ret) @@ -1355,8 +1368,8 @@ public static void Handler_Env_GetBlockCoinbase(int dataOffset) Logger.LogInformation($"Handler_Env_GetBlockCoinbase({dataOffset})"); var frame = VirtualMachine.ExecutionFrames.Peek() as WasmExecutionFrame ?? throw new InvalidOperationException("Cannot call GetBlockCoinbase outside wasm frame"); + frame.UseGas(GasMetering.GetSimpleDataGasCost); UInt160 coinbase = UInt160Utils.Zero; - // Load `zero address` at given memory offset var ret = SafeCopyToMemory(frame.Memory, coinbase.ToBytes().ToArray(), dataOffset); if (!ret) @@ -1368,8 +1381,8 @@ public static void Handler_Env_GetBlockDifficulty(int dataOffset) Logger.LogInformation($"Handler_Env_GetBlockDifficulty({dataOffset})"); var frame = VirtualMachine.ExecutionFrames.Peek() as WasmExecutionFrame ?? throw new InvalidOperationException("Cannot call GetBlockDifficulty outside wasm frame"); + frame.UseGas(GasMetering.GetSimpleDataGasCost); var difficulty = 0; - // Load `zero difficulty` at given memory offset var ret = SafeCopyToMemory(frame.Memory, difficulty.ToBytes().ToArray(), dataOffset); if (!ret) @@ -1381,6 +1394,7 @@ public static void Handler_Env_GetExternalBalance(int addressOffset, int resultO Logger.LogInformation($"Handler_Env_GetExternalBalance({addressOffset}, {resultOffset})"); var frame = VirtualMachine.ExecutionFrames.Peek() as WasmExecutionFrame ?? throw new InvalidOperationException("Cannot call GetExternalBalance outside wasm frame"); + frame.UseGas(GasMetering.GetExternalBalanceGasCost); // Get the address from the given memory offset var snapshot = frame.InvocationContext.Snapshot; @@ -1404,7 +1418,7 @@ public static void Handler_Env_GetExtcodesize(int addressOffset, int resultOffse Logger.LogInformation($"Handler_Env_GetExtcodesize({addressOffset}, {resultOffset})"); var frame = VirtualMachine.ExecutionFrames.Peek() as WasmExecutionFrame ?? throw new InvalidOperationException("Cannot call GetExtcodesize outside wasm frame"); - + frame.UseGas(GasMetering.GetExternalCodeSizeGasCost); // Get the address from the given memory offset var snapshot = frame.InvocationContext.Snapshot; var addressBuffer = SafeCopyFromMemory(frame.Memory, addressOffset, 20); @@ -1428,6 +1442,7 @@ public static void Handler_Env_GetBlockTimestamp(int dataOffset) var frame = VirtualMachine.ExecutionFrames.Peek() as WasmExecutionFrame ?? throw new InvalidOperationException("Cannot call GetBlockTimestamp outside wasm frame"); + frame.UseGas(GasMetering.GetBlockTimestampGasCost); // Get the TotalBlockHeight at the given Snapshot var snapshot = frame.InvocationContext.Snapshot; var blockHeight = snapshot.Blocks.GetTotalBlockHeight(); @@ -1446,6 +1461,7 @@ public static void Handler_Env_GetBlockHash(int numberOffset, int dataOffset) var frame = VirtualMachine.ExecutionFrames.Peek() as WasmExecutionFrame ?? throw new InvalidOperationException("Cannot call Handler_Env_GetBlockHash outside wasm frame"); + frame.UseGas(GasMetering.GetBlockHashGasCost); var snapshot = frame.InvocationContext.Snapshot; var blockNumberBuffer = SafeCopyFromMemory(frame.Memory, numberOffset, 8); if (blockNumberBuffer is null) @@ -1471,6 +1487,7 @@ public static void Handler_Env_GetChainId(int dataOffset) Logger.LogInformation($"Handler_Env_GetChainId()"); var frame = VirtualMachine.ExecutionFrames.Peek() as WasmExecutionFrame ?? throw new InvalidOperationException("Cannot call GetChainId outside wasm frame"); + frame.UseGas(GasMetering.GetSimpleDataGasCost); var chainId = TransactionUtils.ChainId(HardforkHeights.IsHardfork_9Active(frame.InvocationContext.Snapshot.Blocks.GetTotalBlockHeight() + 1)); diff --git a/src/Lachain.Core/Blockchain/VM/GasMetering.cs b/src/Lachain.Core/Blockchain/VM/GasMetering.cs index e90d6cfa4..40d022efa 100644 --- a/src/Lachain.Core/Blockchain/VM/GasMetering.cs +++ b/src/Lachain.Core/Blockchain/VM/GasMetering.cs @@ -6,16 +6,24 @@ public class GasMetering public const ulong DefaultTxCost = 3_000_000; public const ulong InputDataGasPerByte = 10; - public const ulong CopyFromMemoryGasPerByte = 10; - public const ulong CopyToMemoryGasPerByte = 10; - public const ulong GetCallValueGasCost = 100; - public const ulong GetCallSizeGasCost = 10; - public const ulong GetReturnValueGasCost = 100; - public const ulong GetReturnSizeGasCost = 10; - public const ulong CopyCodeValueGasCost = 100; - public const ulong GetCodeSizeGasCost = 10; + public const ulong CopyFromMemoryGasPerByte = 100; + public const ulong CopyToMemoryGasPerByte = 100; + public const ulong GetCallValueGasCost = 10_000; + public const ulong GetCallSizeGasCost = 10_000; + public const ulong GetReturnValueGasCost = 10_000; + public const ulong GetReturnSizeGasCost = 10_000; + public const ulong SetReturnGasCost = 10_000; + public const ulong GetGasLeftGasCost = 100; + public const ulong GetSimpleDataGasCost = 1_000; + public const ulong GetExternalBalanceGasCost = 1_000_000; + public const ulong GetExternalCodeSizeGasCost = 500_000; + public const ulong GetBlockTimestampGasCost = 50_000; + public const ulong GetBlockHashGasCost = 500_000; + public const ulong CopyCodeValueGasCost = 10_000; + public const ulong GetCodeSizeGasCost = 10_000; + public const ulong InvokeContractGasCost = 7_000_000; public const ulong TransferFundsGasCost = 3_000_000; - public const ulong LoadStorageGasCost = 500_000; + public const ulong LoadStorageGasCost = 1_000_000; public const ulong SaveStorageGasCost = 3_000_000; public const ulong KillStorageGasCost = 3_000_000; public const ulong Keccak256GasCost= 0; @@ -24,8 +32,8 @@ public class GasMetering public const ulong Sha256GasPerByte = 100_000; public const ulong Ripemd160GasCost = 0; public const ulong Ripemd160GasPerByte = 100_000; - public const ulong RecoverGasCost = 100_000; - public const ulong VerifyGasCost = 60_000; + public const ulong RecoverGasCost = 1_000_000; + public const ulong VerifyGasCost = 6_000_000; public const ulong WriteEventPerByteGas = SaveStorageGasCost / 32; public const ulong CallDataLoad = 1_000; public const ulong MLoad = 1_000; From aa08c567fcb735ec8e0b3adb84b560e687fb4518 Mon Sep 17 00:00:00 2001 From: sgladkov Date: Fri, 4 Nov 2022 16:11:14 +0300 Subject: [PATCH 02/16] fix failed test --- test/Lachain.CoreTest/RPC/HTTP/Web3/Web3TransactionTests.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/Lachain.CoreTest/RPC/HTTP/Web3/Web3TransactionTests.cs b/test/Lachain.CoreTest/RPC/HTTP/Web3/Web3TransactionTests.cs index f2632c0f1..67b2273d2 100644 --- a/test/Lachain.CoreTest/RPC/HTTP/Web3/Web3TransactionTests.cs +++ b/test/Lachain.CoreTest/RPC/HTTP/Web3/Web3TransactionTests.cs @@ -369,7 +369,7 @@ public void Test_EstimateGas() }; var result = _apiService!.EstimateGas(opts); - Assert.AreEqual(result, "0x2e1d22"); + Assert.AreEqual(result, "0x2eae18"); var receipt = TestUtils.GetRandomTransaction(false); opts = new JObject From 800002302d2557c0e1c862e68ee3ffdab850ca1e Mon Sep 17 00:00:00 2001 From: tbssajal Date: Mon, 9 Jan 2023 00:03:39 +0600 Subject: [PATCH 03/16] added hardfork15 --- src/Lachain.Core/Blockchain/Hardfork/HardforkHeights.cs | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/Lachain.Core/Blockchain/Hardfork/HardforkHeights.cs b/src/Lachain.Core/Blockchain/Hardfork/HardforkHeights.cs index 63485d773..15df2cba5 100644 --- a/src/Lachain.Core/Blockchain/Hardfork/HardforkHeights.cs +++ b/src/Lachain.Core/Blockchain/Hardfork/HardforkHeights.cs @@ -109,6 +109,12 @@ public static bool IsHardfork_16Active(ulong height) return height >= Hardfork_16; } + // adjust gas consumption + public static bool IsHardfork_15Active(ulong height) + { + return height >= Hardfork_15; + } + public static void SetHardforkHeights(HardforkConfig hardforkConfig) { if(alreadySet == true) From 7e3e72400e29782b344f09ea9d471fbd342d340e Mon Sep 17 00:00:00 2001 From: tbssajal Date: Mon, 9 Jan 2023 00:04:13 +0600 Subject: [PATCH 04/16] added method to use new gas price --- src/Lachain.Core/Blockchain/VM/ExternalHandler.cs | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/src/Lachain.Core/Blockchain/VM/ExternalHandler.cs b/src/Lachain.Core/Blockchain/VM/ExternalHandler.cs index e39b6f405..d3a7932fd 100644 --- a/src/Lachain.Core/Blockchain/VM/ExternalHandler.cs +++ b/src/Lachain.Core/Blockchain/VM/ExternalHandler.cs @@ -1551,6 +1551,19 @@ private static bool TransferBalance( ); } } + + private static void UseGas(IExecutionFrame frame, ulong newGasPrice, ulong oldGasPrice) + { + var height = frame.InvocationContext.Snapshot.Blocks.GetTotalBlockHeight(); + if (HardforkHeights.IsHardfork_15Active(height)) + { + frame.UseGas(newGasPrice); + } + else + { + frame.UseGas(oldGasPrice); + } + } private static FunctionImport CreateImport(string methodName) { From c33e4b746a5ca6274f213d0404348e10e18fbe4e Mon Sep 17 00:00:00 2001 From: tbssajal Date: Thu, 19 Jan 2023 02:35:54 +0600 Subject: [PATCH 05/16] updated gas usage --- src/Lachain.Core/Blockchain/VM/GasMetering.cs | 33 +++++++++---------- 1 file changed, 16 insertions(+), 17 deletions(-) diff --git a/src/Lachain.Core/Blockchain/VM/GasMetering.cs b/src/Lachain.Core/Blockchain/VM/GasMetering.cs index 40d022efa..caf4e60a0 100644 --- a/src/Lachain.Core/Blockchain/VM/GasMetering.cs +++ b/src/Lachain.Core/Blockchain/VM/GasMetering.cs @@ -6,24 +6,21 @@ public class GasMetering public const ulong DefaultTxCost = 3_000_000; public const ulong InputDataGasPerByte = 10; - public const ulong CopyFromMemoryGasPerByte = 100; - public const ulong CopyToMemoryGasPerByte = 100; - public const ulong GetCallValueGasCost = 10_000; - public const ulong GetCallSizeGasCost = 10_000; - public const ulong GetReturnValueGasCost = 10_000; - public const ulong GetReturnSizeGasCost = 10_000; - public const ulong SetReturnGasCost = 10_000; + public const ulong CopyFromMemoryGasPerByte = 10; + public const ulong NewCopyFromMemoryGasPerByte = 100; + public const ulong CopyToMemoryGasPerByte = 10; + public const ulong NewCopyToMemoryGasPerByte = 100; + public const ulong GetCallValueGasCost = 100; + public const ulong GetCallSizeGasCost = 10; + public const ulong GetReturnValueGasCost = 100; + public const ulong GetReturnSizeGasCost = 10; + public const ulong SetReturnGasCost = 100; public const ulong GetGasLeftGasCost = 100; - public const ulong GetSimpleDataGasCost = 1_000; - public const ulong GetExternalBalanceGasCost = 1_000_000; - public const ulong GetExternalCodeSizeGasCost = 500_000; - public const ulong GetBlockTimestampGasCost = 50_000; - public const ulong GetBlockHashGasCost = 500_000; - public const ulong CopyCodeValueGasCost = 10_000; - public const ulong GetCodeSizeGasCost = 10_000; + public const ulong CopyCodeValueGasCost = 100; + public const ulong GetCodeSizeGasCost = 10; public const ulong InvokeContractGasCost = 7_000_000; public const ulong TransferFundsGasCost = 3_000_000; - public const ulong LoadStorageGasCost = 1_000_000; + public const ulong LoadStorageGasCost = 500_000; public const ulong SaveStorageGasCost = 3_000_000; public const ulong KillStorageGasCost = 3_000_000; public const ulong Keccak256GasCost= 0; @@ -32,8 +29,10 @@ public class GasMetering public const ulong Sha256GasPerByte = 100_000; public const ulong Ripemd160GasCost = 0; public const ulong Ripemd160GasPerByte = 100_000; - public const ulong RecoverGasCost = 1_000_000; - public const ulong VerifyGasCost = 6_000_000; + public const ulong RecoverGasCost = 100_000; + public const ulong NewRecoverGasCost = 1_000_000; + public const ulong VerifyGasCost = 60_000; + public const ulong NewVerifyGasCost = 1_000_000; public const ulong WriteEventPerByteGas = SaveStorageGasCost / 32; public const ulong CallDataLoad = 1_000; public const ulong MLoad = 1_000; From 274ddb77d545cb5605bb2954f966d97fa377532b Mon Sep 17 00:00:00 2001 From: tbssajal Date: Thu, 19 Jan 2023 02:36:25 +0600 Subject: [PATCH 06/16] using hardfork for new gas usage --- .../Blockchain/VM/ExternalHandler.cs | 84 ++++++++++++------- 1 file changed, 52 insertions(+), 32 deletions(-) diff --git a/src/Lachain.Core/Blockchain/VM/ExternalHandler.cs b/src/Lachain.Core/Blockchain/VM/ExternalHandler.cs index d3a7932fd..beaf32cf0 100644 --- a/src/Lachain.Core/Blockchain/VM/ExternalHandler.cs +++ b/src/Lachain.Core/Blockchain/VM/ExternalHandler.cs @@ -44,6 +44,7 @@ private static InvocationResult DoInternalCall( { Logger.LogInformation($"DoInternalCall({caller.ToHex()}, {address.ToHex()}, {input.ToHex()}, {gasLimit})"); var currentFrame = VirtualMachine.ExecutionFrames.Peek(); + UseGas(currentFrame, GasMetering.InvokeContractGasCost, null); var context = currentFrame.InvocationContext.NextContext(caller); context.Message = message; return ContractInvoker.Invoke(address, context, input, gasLimit); @@ -109,7 +110,7 @@ private static void SetDeployHeight(UInt160 contract, ulong height, ulong gasLim return null; if (offset + length > memory.Size) return null; - frame.UseGas(GasMetering.CopyFromMemoryGasPerByte * (ulong) length); + UseGas(frame, GasMetering.NewCopyFromMemoryGasPerByte * (ulong) length, GasMetering.CopyFromMemoryGasPerByte * (ulong) length); var buffer = new byte[length]; try { @@ -130,7 +131,7 @@ private static bool SafeCopyToMemory(UnmanagedMemory memory, byte[] data, int of var frame = VirtualMachine.ExecutionFrames.Peek(); if (offset < 0 || offset + data.Length > memory.Size) return false; - frame.UseGas(GasMetering.CopyToMemoryGasPerByte * (ulong) data.Length); + UseGas(frame, GasMetering.NewCopyToMemoryGasPerByte * (ulong) data.Length, GasMetering.CopyToMemoryGasPerByte * (ulong) data.Length); try { Marshal.Copy(data, 0, IntPtr.Add(memory.Start, offset), data.Length); @@ -149,6 +150,7 @@ private static int InvokeContract( Logger.LogInformation($"InvokeContract({callSignatureOffset}, {inputLength}, {inputOffset}, {valueOffset}, {gasOffset}, {invocationType})"); var frame = VirtualMachine.ExecutionFrames.Peek() as WasmExecutionFrame ?? throw new InvalidOperationException("Cannot call InvokeContract outside wasm frame"); + UseGas(frame, GasMetering.InvokeContractGasCost, null); var snapshot = frame.InvocationContext.Snapshot; var addressBuffer = SafeCopyFromMemory(frame.Memory, callSignatureOffset, 20); var inputBuffer = SafeCopyFromMemory(frame.Memory, inputOffset, inputLength); @@ -175,9 +177,10 @@ private static int InvokeContract( if (!result) throw new InsufficientFundsException(); - Emit(frame.InvocationContext, Lrc20Interface.EventTransfer, transferFrom, address, value); + Emit(frame, Lrc20Interface.EventTransfer, transferFrom, address, value); } + UseGas(frame, GasMetering.LoadStorageGasCost, null); if (snapshot.Contracts.GetContractByHash(address) is null) { frame.LastChildReturnValue = Array.Empty(); return 0; @@ -329,6 +332,8 @@ int topic3Offset topics ); frame.UseGas(GasMetering.WriteEventPerByteGas * ((ulong)data.Length + 1000UL)); + var topcisDataLength = topics is null ? 0 : topics.Count * 32; + UseGas(frame, GasMetering.WriteEventPerByteGas * (ulong) topcisDataLength, null); frame.InvocationContext.Snapshot.Events.AddEvent(eventObj); } @@ -378,7 +383,7 @@ public static int Handler_Env_Transfer( var result = TransferBalance(transferFrom, address, value, frame); if (!result) throw new InsufficientFundsException(); - Emit(frame.InvocationContext, Lrc20Interface.EventTransfer, transferFrom, address, value); + Emit(frame, Lrc20Interface.EventTransfer, GetHardfork_5CurrentAddressOrDelegate(frame), address, value); } return 0; @@ -394,6 +399,7 @@ public static int Handler_Env_Create(int valueOffset, int dataOffset, int dataLe Value = frame.InvocationContext.Message?.Value ?? UInt256Utils.Zero, Type = InvocationType.Regular, }; + UseGas(frame, GasMetering.LoadStorageGasCost, null); var deployHeight = GetDeployHeight(frame.InvocationContext.Snapshot.Blocks.GetTotalBlockHeight(), frame.CurrentAddress, frame.CurrentAddress, frame.GasLimit, invocationMessage); @@ -419,6 +425,7 @@ private static int Handler_Env_Create_V1(int valueOffset, int dataOffset, int da if (value is null) throw new InvalidContractException("Bad call to Create function"); + UseGas(frame, GasMetering.LoadStorageGasCost, null); if (snapshot.Balances.GetBalance(GetHardfork_5CurrentAddressOrDelegate(frame)) < value) { throw new InsufficientFundsException(); @@ -443,6 +450,7 @@ private static int Handler_Env_Create_V1(int valueOffset, int dataOffset, int da Value = frame.InvocationContext.Message?.Value ?? UInt256Utils.Zero, Type = InvocationType.Regular, }; + UseGas(frame, GasMetering.LoadStorageGasCost, null); var deployHeight = GetDeployHeight(frame.InvocationContext.Snapshot.Blocks.GetTotalBlockHeight(), frame.CurrentAddress, frame.CurrentAddress, frame.GasLimit, invocationMessage); @@ -454,6 +462,7 @@ private static int Handler_Env_Create_V1(int valueOffset, int dataOffset, int da try { + UseGas(frame, GasMetering.SaveStorageGasCost, null); snapshot.Contracts.AddContract(context.Sender, contract); SetDeployHeight(hash, deployHeight, frame.GasLimit, invocationMessage); } @@ -467,7 +476,7 @@ private static int Handler_Env_Create_V1(int valueOffset, int dataOffset, int da frame.UseGas(GasMetering.TransferFundsGasCost); var transferFrom = GetHardfork_5CurrentAddressOrDelegate(frame); TransferBalance(transferFrom, hash, value, frame); - Emit(frame.InvocationContext, Lrc20Interface.EventTransfer, transferFrom, hash, value); + Emit(frame, Lrc20Interface.EventTransfer, transferFrom, hash, value); SafeCopyToMemory(frame.Memory, hash.ToBytes(), resultOffset); @@ -492,6 +501,7 @@ private static int Handler_Env_Create_V2(int valueOffset, int dataOffset, int da if (value is null) throw new InvalidContractException("Bad call to Create function"); + UseGas(frame, GasMetering.LoadStorageGasCost, null); if (snapshot.Balances.GetBalance(GetHardfork_5CurrentAddressOrDelegate(frame)) < value) { throw new InsufficientFundsException(); @@ -519,6 +529,7 @@ private static int Handler_Env_Create_V2(int valueOffset, int dataOffset, int da try { + UseGas(frame, GasMetering.SaveStorageGasCost, null); snapshot.Contracts.AddContract(context.Sender, deploymentContract); } catch (OutOfGasException e) @@ -556,11 +567,13 @@ private static int Handler_Env_Create_V2(int valueOffset, int dataOffset, int da throw new InvalidContractException("Failed to verify runtime contract"); } + UseGas(frame, GasMetering.LoadStorageGasCost, null); var deployHeight = GetDeployHeight(frame.InvocationContext.Snapshot.Blocks.GetTotalBlockHeight(), context.Sender, context.Sender, frame.GasLimit, invocationMessage); try { + UseGas(frame, GasMetering.SaveStorageGasCost, null); snapshot.Contracts.AddContract(context.Sender, runtimeContract); SetDeployHeight(hash, deployHeight, frame.GasLimit, invocationMessage); } @@ -574,7 +587,7 @@ private static int Handler_Env_Create_V2(int valueOffset, int dataOffset, int da frame.UseGas(GasMetering.TransferFundsGasCost); var transferFrom = GetHardfork_5CurrentAddressOrDelegate(frame); TransferBalance(transferFrom, hash, value, frame); - Emit(frame.InvocationContext, Lrc20Interface.EventTransfer, transferFrom, hash, value); + Emit(frame, Lrc20Interface.EventTransfer, transferFrom, hash, value); SafeCopyToMemory(frame.Memory, hash.ToBytes(), resultOffset); @@ -592,6 +605,7 @@ public static int Handler_Env_Create2(int valueOffset, int dataOffset, int dataL Value = frame.InvocationContext.Message?.Value ?? UInt256Utils.Zero, Type = InvocationType.Regular, }; + UseGas(frame, GasMetering.LoadStorageGasCost, null); var deployHeight = GetDeployHeight(frame.InvocationContext.Snapshot.Blocks.GetTotalBlockHeight(), frame.CurrentAddress, frame.CurrentAddress, frame.GasLimit, invocationMessage); @@ -618,6 +632,7 @@ public static int Handler_Env_Create2_V1(int valueOffset, int dataOffset, int da if (value is null) throw new InvalidContractException("Bad call to Create2 function"); + UseGas(frame, GasMetering.LoadStorageGasCost, null); if (snapshot.Balances.GetBalance(GetHardfork_5CurrentAddressOrDelegate(frame)) < value) { throw new InsufficientFundsException(); @@ -640,6 +655,7 @@ public static int Handler_Env_Create2_V1(int valueOffset, int dataOffset, int da Value = frame.InvocationContext.Message?.Value ?? UInt256Utils.Zero, Type = InvocationType.Regular, }; + UseGas(frame, GasMetering.LoadStorageGasCost, null); var deployHeight = GetDeployHeight(frame.InvocationContext.Snapshot.Blocks.GetTotalBlockHeight(), frame.CurrentAddress, frame.CurrentAddress, frame.GasLimit, invocationMessage); @@ -651,6 +667,7 @@ public static int Handler_Env_Create2_V1(int valueOffset, int dataOffset, int da try { + UseGas(frame, GasMetering.SaveStorageGasCost, null); snapshot.Contracts.AddContract(context.Sender, contract); SetDeployHeight(hash, deployHeight, frame.GasLimit, invocationMessage); } @@ -664,7 +681,7 @@ public static int Handler_Env_Create2_V1(int valueOffset, int dataOffset, int da frame.UseGas(GasMetering.TransferFundsGasCost); var transferFrom = GetHardfork_5CurrentAddressOrDelegate(frame); TransferBalance(transferFrom, hash, value, frame); - Emit(frame.InvocationContext, Lrc20Interface.EventTransfer, transferFrom, hash, value); + Emit(frame, Lrc20Interface.EventTransfer, transferFrom, hash, value); SafeCopyToMemory(frame.Memory, hash.ToBytes(), resultOffset); @@ -690,6 +707,7 @@ public static int Handler_Env_Create2_V2(int valueOffset, int dataOffset, int da if (value is null) throw new InvalidContractException("Bad call to Create2 function"); + UseGas(frame, GasMetering.LoadStorageGasCost, null); if (snapshot.Balances.GetBalance(GetHardfork_5CurrentAddressOrDelegate(frame)) < value) { throw new InsufficientFundsException(); @@ -715,6 +733,7 @@ public static int Handler_Env_Create2_V2(int valueOffset, int dataOffset, int da try { + UseGas(frame, GasMetering.SaveStorageGasCost, null); snapshot.Contracts.AddContract(context.Sender, deploymentContract); } catch (OutOfGasException e) @@ -747,6 +766,7 @@ public static int Handler_Env_Create2_V2(int valueOffset, int dataOffset, int da // runtime code var runtimeContract = new Contract(hash, status.ReturnValue); + UseGas(frame, GasMetering.LoadStorageGasCost, null); var deployHeight = GetDeployHeight(frame.InvocationContext.Snapshot.Blocks.GetTotalBlockHeight(), frame.CurrentAddress, frame.CurrentAddress, frame.GasLimit, invocationMessage); @@ -757,6 +777,7 @@ public static int Handler_Env_Create2_V2(int valueOffset, int dataOffset, int da try { + UseGas(frame, GasMetering.SaveStorageGasCost, null); snapshot.Contracts.AddContract(context.Sender, runtimeContract); SetDeployHeight(hash, deployHeight, frame.GasLimit, invocationMessage); } @@ -770,7 +791,7 @@ public static int Handler_Env_Create2_V2(int valueOffset, int dataOffset, int da frame.UseGas(GasMetering.TransferFundsGasCost); var transferFrom = GetHardfork_5CurrentAddressOrDelegate(frame); TransferBalance(transferFrom, hash, value, frame); - Emit(frame.InvocationContext, Lrc20Interface.EventTransfer, transferFrom, hash, value); + Emit(frame, Lrc20Interface.EventTransfer, transferFrom, hash, value); SafeCopyToMemory(frame.Memory, hash.ToBytes(), resultOffset); @@ -805,6 +826,7 @@ public static int Handler_Env_GetCodeSize() var frame = VirtualMachine.ExecutionFrames.Peek() as WasmExecutionFrame ?? throw new InvalidOperationException("Cannot call GetCodeSize outside wasm frame"); frame.UseGas(GasMetering.GetCodeSizeGasCost); + UseGas(frame, GasMetering.LoadStorageGasCost, null); var byteCode = frame.InvocationContext.Snapshot.Contracts.GetContractByHash(frame.CurrentAddress)?.ByteCode ?? Array.Empty(); return byteCode.Length; } @@ -815,6 +837,7 @@ public static void Handler_Env_CopyCodeValue(int resultOffset, int dataOffset, i var frame = VirtualMachine.ExecutionFrames.Peek() as WasmExecutionFrame ?? throw new InvalidOperationException("Cannot call CopyCodeValue outside wasm frame"); frame.UseGas(GasMetering.CopyCodeValueGasCost); + UseGas(frame, GasMetering.LoadStorageGasCost, null); var byteCode = frame.InvocationContext.Snapshot.Contracts.GetContractByHash(frame.CurrentAddress)?.ByteCode ?? Array.Empty(); if (dataOffset < 0 || length < 0 || dataOffset + length > byteCode.Length) throw new InvalidContractException("Bad CopyCodeValue call"); @@ -1034,6 +1057,7 @@ public static int Handler_Env_GetStorageStringSize(int keyOffset) var frame = VirtualMachine.ExecutionFrames.Peek() as WasmExecutionFrame ?? throw new InvalidOperationException("Cannot call GETSTORAGESTRINGSIZE outside wasm frame"); frame.UseGas(GasMetering.GetReturnSizeGasCost); + UseGas(frame, GasMetering.LoadStorageGasCost, null); var key = SafeCopyFromMemory(frame.Memory, keyOffset, 32); if (key is null) @@ -1060,7 +1084,7 @@ public static void Handler_Env_SetReturn(int offset, int length) Logger.LogInformation($"Handler_Env_SetReturn({offset}, {length})"); var frame = VirtualMachine.ExecutionFrames.Peek() as WasmExecutionFrame ?? throw new InvalidOperationException("Cannot call SETRETURN outside wasm frame"); - frame.UseGas(GasMetering.SetReturnGasCost); + UseGas(frame, GasMetering.SetReturnGasCost, null); var ret = SafeCopyFromMemory(frame.Memory, offset, length); Logger.LogInformation($"ret: {ret.ToHex()}"); if (ret is null) @@ -1075,7 +1099,6 @@ public static void Handler_Env_GetSender(int dataOffset) ?? throw new InvalidOperationException("Cannot call GETSENDER outside wasm frame"); var data = (frame.InvocationContext.Message?.Sender ?? frame.InvocationContext.Sender).ToBytes(); Logger.LogInformation($"Data: {data.ToHex()}"); - frame.UseGas(GasMetering.GetSimpleDataGasCost); var ret = SafeCopyToMemory(frame.Memory, data, dataOffset); if (!ret) throw new InvalidContractException("Bad call to GETSENDER"); @@ -1086,7 +1109,7 @@ public static void Handler_Env_GetGasLeft(int dataOffset) Logger.LogInformation($"Handler_Env_GetGasLeft({dataOffset})"); var frame = VirtualMachine.ExecutionFrames.Peek() as WasmExecutionFrame ?? throw new InvalidOperationException("Cannot call GETGASLEFT outside wasm frame"); - frame.UseGas(GasMetering.GetGasLeftGasCost); + UseGas(frame, GasMetering.GetGasLeftGasCost, null); var data = (frame.GasLimit - frame.GasUsed).ToBytes().ToArray(); var ret = SafeCopyToMemory(frame.Memory, data, dataOffset); if (!ret) @@ -1098,7 +1121,6 @@ public static void Handler_Env_GetTxOrigin(int dataOffset) Logger.LogInformation($"Handler_Env_GetTxOrigin({dataOffset})"); var frame = VirtualMachine.ExecutionFrames.Peek() as WasmExecutionFrame ?? throw new InvalidOperationException("Cannot call GETTXORIGIN outside wasm frame"); - frame.UseGas(GasMetering.GetSimpleDataGasCost); var data = frame.InvocationContext.Sender.ToBytes(); var ret = SafeCopyToMemory(frame.Memory, data, dataOffset); if (!ret) @@ -1110,7 +1132,6 @@ public static void Handler_Env_GetTxGasPrice(int dataOffset) Logger.LogInformation($"Handler_Env_GetTxGasPrice({dataOffset})"); var frame = VirtualMachine.ExecutionFrames.Peek() as WasmExecutionFrame ?? throw new InvalidOperationException("Cannot call GETTXGASPRICE outside wasm frame"); - frame.UseGas(GasMetering.GetSimpleDataGasCost); var data = frame.InvocationContext.Receipt.Transaction.GasPrice.ToBytes().ToArray(); var ret = SafeCopyToMemory(frame.Memory, data, dataOffset); if (!ret) @@ -1122,6 +1143,7 @@ public static void Handler_Env_GetBlockNumber(int dataOffset) Logger.LogInformation($"Handler_Env_GetBlockNumber({dataOffset})"); var frame = VirtualMachine.ExecutionFrames.Peek() as WasmExecutionFrame ?? throw new InvalidOperationException("Cannot call GETBLOCKNUMBER outside wasm frame"); + UseGas(frame, GasMetering.LoadStorageGasCost, null); var data = frame.InvocationContext.Snapshot.Blocks.GetTotalBlockHeight().ToBytes().ToArray(); var ret = SafeCopyToMemory(frame.Memory, data, dataOffset); if (!ret) @@ -1187,7 +1209,7 @@ public static void Handler_Env_CryptoRecoverV1(int hashOffset, int v, int rOffse { bool useNewChainId = HardforkHeights.IsHardfork_9Active(frame.InvocationContext.Snapshot.Blocks.GetTotalBlockHeight() + 1); - frame.UseGas(GasMetering.RecoverGasCost); + UseGas(frame, GasMetering.NewRecoverGasCost, GasMetering.RecoverGasCost); var hash = SafeCopyFromMemory(frame.Memory, hashOffset, 32) ?? throw new InvalidOperationException(); var sig = new byte[SignatureUtils.Length(useNewChainId)]; @@ -1218,7 +1240,7 @@ public static void Handler_Env_CryptoRecoverV2(int hashOffset, int v, int rOffse { bool useNewChainId = HardforkHeights.IsHardfork_9Active(frame.InvocationContext.Snapshot.Blocks.GetTotalBlockHeight() + 1); - frame.UseGas(GasMetering.RecoverGasCost); + UseGas(frame, GasMetering.NewRecoverGasCost, GasMetering.RecoverGasCost); var hash = SafeCopyFromMemory(frame.Memory, hashOffset, 32) ?? throw new InvalidOperationException(); var sigLength = SignatureUtils.Length(useNewChainId); @@ -1267,7 +1289,7 @@ public static void Handler_Env_CryptoVerify(int messageOffset, int messageLength ?? throw new InvalidOperationException("Cannot call ECVERIFY outside wasm frame"); bool useNewChainId = HardforkHeights.IsHardfork_9Active(frame.InvocationContext.Snapshot.Blocks.GetTotalBlockHeight() + 1); - frame.UseGas(GasMetering.VerifyGasCost); + UseGas(frame, GasMetering.NewVerifyGasCost, GasMetering.VerifyGasCost); var message = SafeCopyFromMemory(frame.Memory, messageOffset, messageLength) ?? throw new InvalidOperationException(); var sig = SafeCopyFromMemory(frame.Memory, signatureOffset, SignatureUtils.Length(useNewChainId)) ?? @@ -1283,7 +1305,6 @@ public static void Handler_Env_GetTransferredFunds(int dataOffset) Logger.LogInformation($"Handler_Env_GetTransferredFunds({dataOffset})"); var frame = VirtualMachine.ExecutionFrames.Peek() as WasmExecutionFrame ?? throw new InvalidOperationException("Cannot call GETCALLVALUE outside wasm frame"); - frame.UseGas(GasMetering.GetSimpleDataGasCost); var data = frame.InvocationContext.Value.ToBytes(); var ret = SafeCopyToMemory(frame.Memory, data, dataOffset); if (!ret) @@ -1295,7 +1316,6 @@ public static void Handler_Env_GetTransactionHash(int dataOffset) Logger.LogInformation($"Handler_Env_GetTransactionHash({dataOffset})"); var frame = VirtualMachine.ExecutionFrames.Peek() as WasmExecutionFrame ?? throw new InvalidOperationException("Cannot call TXHASH outside wasm frame"); - frame.UseGas(GasMetering.GetSimpleDataGasCost); var data = frame.InvocationContext.TransactionHash.ToBytes(); var ret = SafeCopyToMemory(frame.Memory, data, dataOffset); if (!ret) @@ -1331,7 +1351,6 @@ public static void Handler_Env_GetAddress(int resultOffset) Logger.LogInformation($"Handler_Env_GetAddress({resultOffset})"); var frame = VirtualMachine.ExecutionFrames.Peek() as WasmExecutionFrame ?? throw new InvalidOperationException("Cannot call GetAddress outside wasm frame"); - frame.UseGas(GasMetering.GetSimpleDataGasCost); var result = (frame.InvocationContext.Message?.Delegate ?? frame.CurrentAddress).ToBytes(); var ret = SafeCopyToMemory(frame.Memory, result, resultOffset); if (!ret) @@ -1343,7 +1362,6 @@ public static void Handler_Env_GetMsgValue(int dataOffset) Logger.LogInformation($"Handler_Env_GetMsgValue({dataOffset})"); var frame = VirtualMachine.ExecutionFrames.Peek() as WasmExecutionFrame ?? throw new InvalidOperationException("Cannot call GetMsgValue outside wasm frame"); - frame.UseGas(GasMetering.GetSimpleDataGasCost); var data = (frame.InvocationContext.Message?.Value ?? frame.InvocationContext.Value).ToBytes().Reverse().ToArray(); var ret = SafeCopyToMemory(frame.Memory, data, dataOffset); if (!ret) @@ -1355,7 +1373,6 @@ public static void Handler_Env_GetBlockGasLimit(int dataOffset) Logger.LogInformation($"Handler_Env_GetBlockGasLimit({dataOffset})"); var frame = VirtualMachine.ExecutionFrames.Peek() as WasmExecutionFrame ?? throw new InvalidOperationException("Cannot call GetBlockGasLimit outside wasm frame"); - frame.UseGas(GasMetering.GetSimpleDataGasCost); const ulong defaultBlockGasLimit = GasMetering.DefaultBlockGasLimit; // Load `default block gasLimit` at given memory offset var ret = SafeCopyToMemory(frame.Memory, defaultBlockGasLimit.ToBytes().ToArray(), dataOffset); @@ -1368,7 +1385,6 @@ public static void Handler_Env_GetBlockCoinbase(int dataOffset) Logger.LogInformation($"Handler_Env_GetBlockCoinbase({dataOffset})"); var frame = VirtualMachine.ExecutionFrames.Peek() as WasmExecutionFrame ?? throw new InvalidOperationException("Cannot call GetBlockCoinbase outside wasm frame"); - frame.UseGas(GasMetering.GetSimpleDataGasCost); UInt160 coinbase = UInt160Utils.Zero; // Load `zero address` at given memory offset var ret = SafeCopyToMemory(frame.Memory, coinbase.ToBytes().ToArray(), dataOffset); @@ -1381,7 +1397,6 @@ public static void Handler_Env_GetBlockDifficulty(int dataOffset) Logger.LogInformation($"Handler_Env_GetBlockDifficulty({dataOffset})"); var frame = VirtualMachine.ExecutionFrames.Peek() as WasmExecutionFrame ?? throw new InvalidOperationException("Cannot call GetBlockDifficulty outside wasm frame"); - frame.UseGas(GasMetering.GetSimpleDataGasCost); var difficulty = 0; // Load `zero difficulty` at given memory offset var ret = SafeCopyToMemory(frame.Memory, difficulty.ToBytes().ToArray(), dataOffset); @@ -1394,7 +1409,6 @@ public static void Handler_Env_GetExternalBalance(int addressOffset, int resultO Logger.LogInformation($"Handler_Env_GetExternalBalance({addressOffset}, {resultOffset})"); var frame = VirtualMachine.ExecutionFrames.Peek() as WasmExecutionFrame ?? throw new InvalidOperationException("Cannot call GetExternalBalance outside wasm frame"); - frame.UseGas(GasMetering.GetExternalBalanceGasCost); // Get the address from the given memory offset var snapshot = frame.InvocationContext.Snapshot; @@ -1404,6 +1418,7 @@ public static void Handler_Env_GetExternalBalance(int addressOffset, int resultO var address = addressBuffer.Take(20).ToArray().ToUInt160(); // Get balance at the given addres + UseGas(frame, GasMetering.LoadStorageGasCost, null); var balance = snapshot.Balances.GetBalance(address); // Load balance at the given resultOffset @@ -1418,7 +1433,6 @@ public static void Handler_Env_GetExtcodesize(int addressOffset, int resultOffse Logger.LogInformation($"Handler_Env_GetExtcodesize({addressOffset}, {resultOffset})"); var frame = VirtualMachine.ExecutionFrames.Peek() as WasmExecutionFrame ?? throw new InvalidOperationException("Cannot call GetExtcodesize outside wasm frame"); - frame.UseGas(GasMetering.GetExternalCodeSizeGasCost); // Get the address from the given memory offset var snapshot = frame.InvocationContext.Snapshot; var addressBuffer = SafeCopyFromMemory(frame.Memory, addressOffset, 20); @@ -1427,6 +1441,7 @@ public static void Handler_Env_GetExtcodesize(int addressOffset, int resultOffse var address = addressBuffer.Take(20).ToArray().ToUInt160(); // Get contract at the given address + UseGas(frame, GasMetering.LoadStorageGasCost, null); var contract = snapshot.Contracts.GetContractByHash(address); // Load contract size at the given resultOffset @@ -1442,8 +1457,8 @@ public static void Handler_Env_GetBlockTimestamp(int dataOffset) var frame = VirtualMachine.ExecutionFrames.Peek() as WasmExecutionFrame ?? throw new InvalidOperationException("Cannot call GetBlockTimestamp outside wasm frame"); - frame.UseGas(GasMetering.GetBlockTimestampGasCost); // Get the TotalBlockHeight at the given Snapshot + UseGas(frame, GasMetering.LoadStorageGasCost, null); var snapshot = frame.InvocationContext.Snapshot; var blockHeight = snapshot.Blocks.GetTotalBlockHeight(); @@ -1461,7 +1476,6 @@ public static void Handler_Env_GetBlockHash(int numberOffset, int dataOffset) var frame = VirtualMachine.ExecutionFrames.Peek() as WasmExecutionFrame ?? throw new InvalidOperationException("Cannot call Handler_Env_GetBlockHash outside wasm frame"); - frame.UseGas(GasMetering.GetBlockHashGasCost); var snapshot = frame.InvocationContext.Snapshot; var blockNumberBuffer = SafeCopyFromMemory(frame.Memory, numberOffset, 8); if (blockNumberBuffer is null) @@ -1469,6 +1483,7 @@ public static void Handler_Env_GetBlockHash(int numberOffset, int dataOffset) var blockNumber = BitConverter.ToUInt64(blockNumberBuffer, 0); // Get block at the given height + UseGas(frame, GasMetering.LoadStorageGasCost, null); var block = snapshot.Blocks.GetBlockByHeight(blockNumber); // Get block's hash @@ -1487,7 +1502,6 @@ public static void Handler_Env_GetChainId(int dataOffset) Logger.LogInformation($"Handler_Env_GetChainId()"); var frame = VirtualMachine.ExecutionFrames.Peek() as WasmExecutionFrame ?? throw new InvalidOperationException("Cannot call GetChainId outside wasm frame"); - frame.UseGas(GasMetering.GetSimpleDataGasCost); var chainId = TransactionUtils.ChainId(HardforkHeights.IsHardfork_9Active(frame.InvocationContext.Snapshot.Blocks.GetTotalBlockHeight() + 1)); @@ -1552,16 +1566,18 @@ private static bool TransferBalance( } } - private static void UseGas(IExecutionFrame frame, ulong newGasPrice, ulong oldGasPrice) + private static void UseGas(IExecutionFrame frame, ulong? newGasPrice, ulong? oldGasPrice) { var height = frame.InvocationContext.Snapshot.Blocks.GetTotalBlockHeight(); if (HardforkHeights.IsHardfork_15Active(height)) { - frame.UseGas(newGasPrice); + if (newGasPrice.HasValue) + frame.UseGas(newGasPrice.Value); } else { - frame.UseGas(oldGasPrice); + if (oldGasPrice.HasValue) + frame.UseGas(oldGasPrice.Value); } } @@ -1649,10 +1665,11 @@ private static string PrettyParam(dynamic param) }; } - private static void Emit(InvocationContext context, string eventSignature, params dynamic[] values) + private static void Emit(IExecutionFrame frame, string eventSignature, params dynamic[] values) { var eventData = ContractEncoder.Encode(null, values); EventObject eventObj; + var context = frame.InvocationContext; if (Lrc20Interface.EventTransfer == eventSignature && HardforkHeights.IsHardfork_6Active(context.Snapshot.Blocks.GetTotalBlockHeight())) { @@ -1664,6 +1681,9 @@ private static void Emit(InvocationContext context, string eventSignature, param Buffer.BlockCopy(eventData, 64, value, 0, 32); topics.Add(from.ToUInt256()); topics.Add(to.ToUInt256()); + UseGas(frame, GasMetering.WriteEventPerByteGas * ((ulong)value.Length + 32), null); + var topcisDataLength = topics.Count * 32; + UseGas(frame, GasMetering.WriteEventPerByteGas * (ulong) topcisDataLength, null); eventObj = new EventObject( new Event From 1b6f614e443b37a4fd10a0e0682473e3b65780d0 Mon Sep 17 00:00:00 2001 From: tbssajal Date: Thu, 19 Jan 2023 02:38:11 +0600 Subject: [PATCH 07/16] fake test --- .../StorageIntergrationTest.cs | 75 +++++++++++++++++++ 1 file changed, 75 insertions(+) diff --git a/test/Lachain.StorageTest/StorageIntergrationTest.cs b/test/Lachain.StorageTest/StorageIntergrationTest.cs index bda218398..1679b6cb5 100644 --- a/test/Lachain.StorageTest/StorageIntergrationTest.cs +++ b/test/Lachain.StorageTest/StorageIntergrationTest.cs @@ -1,3 +1,4 @@ +using System; using System.IO; using System.Reflection; using Lachain.Core.CLI; @@ -5,7 +6,9 @@ using Lachain.Core.DI; using Lachain.Core.DI.Modules; using Lachain.Core.DI.SimpleInjector; +using Lachain.Crypto; using Lachain.Storage.State; +using Lachain.Utility.Serialization; using Lachain.Utility.Utils; using Lachain.UtilityTest; using NUnit.Framework; @@ -74,6 +77,78 @@ public void Teardown() TestUtils.DeleteTestChainData(); } + [Test] + public void Test() + { + var crypto = CryptoProvider.GetCrypto(); + int total = 1000_000; + int commitSize = 100000; + var startTime = TimeUtils.CurrentTimeMillis(); + for (int iter = 0; iter < total / commitSize; iter++) + { + var snapshot = _stateManager.NewSnapshot(); + for (int tx = 0; tx < commitSize; tx++) + { + var receipt = TestUtils.GetRandomTransaction(true); + var block = new Block + { + Header = new BlockHeader + { + Index = (ulong) iter * (ulong) commitSize + (ulong) tx + }, + Hash = TestUtils.GetRandomBytes(32).ToUInt256(), + TransactionHashes = { new UInt256[] { receipt.Hash } } + }; + snapshot.Blocks.AddBlock(block); + snapshot.Transactions.AddTransaction(receipt, TransactionStatus.Executed); + } + _stateManager.Approve(); + _stateManager.Commit(); + } + System.Console.WriteLine(TimeUtils.CurrentTimeMillis() - startTime); + ulong totalTime = 0; + var totalTest = 100000; + ulong minTime = 1000000000000; + ulong maxTime = 0; + for (int iter = 0; iter < totalTest; iter++) + { + var randomUInt = crypto.GenerateRandomBytes(4).AsReadOnlySpan().ToUInt32() % total; + var now = TimeUtils.CurrentTimeMillis(); + var block = _stateManager.LastApprovedSnapshot.Blocks.GetBlockByHeight((ulong) randomUInt); + var receipt = _stateManager.LastApprovedSnapshot.Transactions.GetTransactionByHash(block!.TransactionHashes[0]); + var timeSpent = TimeUtils.CurrentTimeMillis() - now; + minTime = Math.Min(minTime, timeSpent); + maxTime = Math.Max(maxTime, timeSpent); + // System.Console.WriteLine(timeSpent); + totalTime += timeSpent; + } + System.Console.WriteLine("average to read: " + 1.0 * totalTime / totalTest); + System.Console.WriteLine("max time: " + maxTime); + System.Console.WriteLine("min time: " + minTime); + + totalTime = 0; + minTime = 1000000000000; + maxTime = 0; + var snapshotToWrite = _stateManager.NewSnapshot(); + for (int iter = 0; iter < totalTest; iter++) + { + var now = TimeUtils.CurrentTimeMillis(); + var receipt = TestUtils.GetRandomTransaction(true); + snapshotToWrite.Transactions.AddTransaction(receipt, TransactionStatus.Executed); + var timeSpent = TimeUtils.CurrentTimeMillis() - now; + minTime = Math.Min(minTime, timeSpent); + maxTime = Math.Max(maxTime, timeSpent); + // System.Console.WriteLine(timeSpent); + totalTime += timeSpent; + } + _stateManager.Approve(); + _stateManager.Commit(); + System.Console.WriteLine("average to write: " + 1.0 * totalTime / totalTest); + System.Console.WriteLine("max time: " + maxTime); + System.Console.WriteLine("min time: " + minTime); + + } + [Test] public void Test_AddTryGetRandom() { From 4527a5cf9ab35deb2268ea9c33cd4803616bf82e Mon Sep 17 00:00:00 2001 From: tbssajal Date: Thu, 19 Jan 2023 02:50:02 +0600 Subject: [PATCH 08/16] added hardfork 16 --- src/Lachain.Core/Blockchain/Hardfork/HardforkHeights.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Lachain.Core/Blockchain/Hardfork/HardforkHeights.cs b/src/Lachain.Core/Blockchain/Hardfork/HardforkHeights.cs index 15df2cba5..2621e1c7b 100644 --- a/src/Lachain.Core/Blockchain/Hardfork/HardforkHeights.cs +++ b/src/Lachain.Core/Blockchain/Hardfork/HardforkHeights.cs @@ -110,9 +110,9 @@ public static bool IsHardfork_16Active(ulong height) } // adjust gas consumption - public static bool IsHardfork_15Active(ulong height) + public static bool IsHardfork_16Active(ulong height) { - return height >= Hardfork_15; + return height >= Hardfork_16; } public static void SetHardforkHeights(HardforkConfig hardforkConfig) From 33397847afb5f0933fcca4a38cc9ab2a7da66fda Mon Sep 17 00:00:00 2001 From: tbssajal Date: Thu, 19 Jan 2023 02:53:51 +0600 Subject: [PATCH 09/16] removed unnecessary test --- .../StorageIntergrationTest.cs | 72 ------------------- 1 file changed, 72 deletions(-) diff --git a/test/Lachain.StorageTest/StorageIntergrationTest.cs b/test/Lachain.StorageTest/StorageIntergrationTest.cs index 1679b6cb5..f44e8428b 100644 --- a/test/Lachain.StorageTest/StorageIntergrationTest.cs +++ b/test/Lachain.StorageTest/StorageIntergrationTest.cs @@ -77,78 +77,6 @@ public void Teardown() TestUtils.DeleteTestChainData(); } - [Test] - public void Test() - { - var crypto = CryptoProvider.GetCrypto(); - int total = 1000_000; - int commitSize = 100000; - var startTime = TimeUtils.CurrentTimeMillis(); - for (int iter = 0; iter < total / commitSize; iter++) - { - var snapshot = _stateManager.NewSnapshot(); - for (int tx = 0; tx < commitSize; tx++) - { - var receipt = TestUtils.GetRandomTransaction(true); - var block = new Block - { - Header = new BlockHeader - { - Index = (ulong) iter * (ulong) commitSize + (ulong) tx - }, - Hash = TestUtils.GetRandomBytes(32).ToUInt256(), - TransactionHashes = { new UInt256[] { receipt.Hash } } - }; - snapshot.Blocks.AddBlock(block); - snapshot.Transactions.AddTransaction(receipt, TransactionStatus.Executed); - } - _stateManager.Approve(); - _stateManager.Commit(); - } - System.Console.WriteLine(TimeUtils.CurrentTimeMillis() - startTime); - ulong totalTime = 0; - var totalTest = 100000; - ulong minTime = 1000000000000; - ulong maxTime = 0; - for (int iter = 0; iter < totalTest; iter++) - { - var randomUInt = crypto.GenerateRandomBytes(4).AsReadOnlySpan().ToUInt32() % total; - var now = TimeUtils.CurrentTimeMillis(); - var block = _stateManager.LastApprovedSnapshot.Blocks.GetBlockByHeight((ulong) randomUInt); - var receipt = _stateManager.LastApprovedSnapshot.Transactions.GetTransactionByHash(block!.TransactionHashes[0]); - var timeSpent = TimeUtils.CurrentTimeMillis() - now; - minTime = Math.Min(minTime, timeSpent); - maxTime = Math.Max(maxTime, timeSpent); - // System.Console.WriteLine(timeSpent); - totalTime += timeSpent; - } - System.Console.WriteLine("average to read: " + 1.0 * totalTime / totalTest); - System.Console.WriteLine("max time: " + maxTime); - System.Console.WriteLine("min time: " + minTime); - - totalTime = 0; - minTime = 1000000000000; - maxTime = 0; - var snapshotToWrite = _stateManager.NewSnapshot(); - for (int iter = 0; iter < totalTest; iter++) - { - var now = TimeUtils.CurrentTimeMillis(); - var receipt = TestUtils.GetRandomTransaction(true); - snapshotToWrite.Transactions.AddTransaction(receipt, TransactionStatus.Executed); - var timeSpent = TimeUtils.CurrentTimeMillis() - now; - minTime = Math.Min(minTime, timeSpent); - maxTime = Math.Max(maxTime, timeSpent); - // System.Console.WriteLine(timeSpent); - totalTime += timeSpent; - } - _stateManager.Approve(); - _stateManager.Commit(); - System.Console.WriteLine("average to write: " + 1.0 * totalTime / totalTest); - System.Console.WriteLine("max time: " + maxTime); - System.Console.WriteLine("min time: " + minTime); - - } - [Test] public void Test_AddTryGetRandom() { From dd64ebf441742cef9c68cbd089206fbc0af5acc0 Mon Sep 17 00:00:00 2001 From: tbssajal Date: Thu, 19 Jan 2023 14:34:00 +0600 Subject: [PATCH 10/16] fixed bug --- src/Lachain.Core/Blockchain/VM/ExternalHandler.cs | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/src/Lachain.Core/Blockchain/VM/ExternalHandler.cs b/src/Lachain.Core/Blockchain/VM/ExternalHandler.cs index beaf32cf0..7e56a8b99 100644 --- a/src/Lachain.Core/Blockchain/VM/ExternalHandler.cs +++ b/src/Lachain.Core/Blockchain/VM/ExternalHandler.cs @@ -260,7 +260,6 @@ public static void Handler_Env_CopyCallValue(int from, int to, int offset) ?? throw new InvalidOperationException("Cannot call COPYCALLVALUE outside wasm frame"); if (from < 0 || to > frame.Input.Length || from > to) throw new InvalidContractException("Copy to contract memory failed: bad range"); - frame.UseGas(GasMetering.CopyCodeValueGasCost); if (!SafeCopyToMemory(frame.Memory, frame.Input.Skip(from).Take(to - from).ToArray(), offset)) throw new InvalidContractException("Copy to contract memory failed"); } @@ -331,7 +330,7 @@ int topic3Offset }, topics ); - frame.UseGas(GasMetering.WriteEventPerByteGas * ((ulong)data.Length + 1000UL)); + UseGas(frame, GasMetering.WriteEventPerByteGas * ((ulong)data.Length + 32), null); var topcisDataLength = topics is null ? 0 : topics.Count * 32; UseGas(frame, GasMetering.WriteEventPerByteGas * (ulong) topcisDataLength, null); frame.InvocationContext.Snapshot.Events.AddEvent(eventObj); @@ -383,7 +382,7 @@ public static int Handler_Env_Transfer( var result = TransferBalance(transferFrom, address, value, frame); if (!result) throw new InsufficientFundsException(); - Emit(frame, Lrc20Interface.EventTransfer, GetHardfork_5CurrentAddressOrDelegate(frame), address, value); + Emit(frame, Lrc20Interface.EventTransfer, transferFrom, address, value); } return 0; @@ -1353,8 +1352,11 @@ public static void Handler_Env_GetAddress(int resultOffset) ?? throw new InvalidOperationException("Cannot call GetAddress outside wasm frame"); var result = (frame.InvocationContext.Message?.Delegate ?? frame.CurrentAddress).ToBytes(); var ret = SafeCopyToMemory(frame.Memory, result, resultOffset); - if (!ret) - throw new InvalidContractException("Bad call to (get_address)"); + if (HardforkHeights.IsHardfork_16Active(frame.InvocationContext.Snapshot.Blocks.GetTotalBlockHeight())) + { + if (!ret) + throw new InvalidContractException("Bad call to (get_address)"); + } } public static void Handler_Env_GetMsgValue(int dataOffset) @@ -1569,7 +1571,7 @@ private static bool TransferBalance( private static void UseGas(IExecutionFrame frame, ulong? newGasPrice, ulong? oldGasPrice) { var height = frame.InvocationContext.Snapshot.Blocks.GetTotalBlockHeight(); - if (HardforkHeights.IsHardfork_15Active(height)) + if (HardforkHeights.IsHardfork_16Active(height)) { if (newGasPrice.HasValue) frame.UseGas(newGasPrice.Value); From 6c744b0d124d44807abda6bbab4d6160f50e6484 Mon Sep 17 00:00:00 2001 From: tbssajal Date: Fri, 20 Jan 2023 23:00:02 +0600 Subject: [PATCH 11/16] fixed bug --- .../Blockchain/VM/ExternalHandler.cs | 119 ++++++++++++------ src/Lachain.Core/Blockchain/VM/GasMetering.cs | 2 +- 2 files changed, 82 insertions(+), 39 deletions(-) diff --git a/src/Lachain.Core/Blockchain/VM/ExternalHandler.cs b/src/Lachain.Core/Blockchain/VM/ExternalHandler.cs index 7e56a8b99..cbe92b9bc 100644 --- a/src/Lachain.Core/Blockchain/VM/ExternalHandler.cs +++ b/src/Lachain.Core/Blockchain/VM/ExternalHandler.cs @@ -35,6 +35,7 @@ private static UInt160 GetHardfork_5CurrentAddressOrDelegate(IExecutionFrame fra return frame.CurrentAddress; } + // use GasMetering.InvokeContractGasCost before calling DoInternalCall private static InvocationResult DoInternalCall( UInt160 caller, UInt160 address, @@ -44,24 +45,30 @@ private static InvocationResult DoInternalCall( { Logger.LogInformation($"DoInternalCall({caller.ToHex()}, {address.ToHex()}, {input.ToHex()}, {gasLimit})"); var currentFrame = VirtualMachine.ExecutionFrames.Peek(); - UseGas(currentFrame, GasMetering.InvokeContractGasCost, null); var context = currentFrame.InvocationContext.NextContext(caller); context.Message = message; return ContractInvoker.Invoke(address, context, input, gasLimit); } - private static ulong GetDeployHeight(ulong currentHeight, UInt160 contract, UInt160 caller, ulong gasLimit, InvocationMessage message) + private static ulong GetDeployHeight(IExecutionFrame frame, ulong currentHeight, UInt160 contract, UInt160 caller, ulong gasLimit, InvocationMessage message) { if (HardforkHeights.IsHardfork_7Active(currentHeight)) - return GetDeployHeightV2(currentHeight, contract, caller, gasLimit, message); - return GetDeployHeightV1(currentHeight, contract, caller, gasLimit, message); + return GetDeployHeightV2(frame, currentHeight, contract, caller, gasLimit, message); + return GetDeployHeightV1(frame, currentHeight, contract, caller, gasLimit, message); } - private static ulong GetDeployHeightV1(ulong currentHeight, UInt160 contract, UInt160 caller, ulong gasLimit, InvocationMessage message) + private static ulong GetDeployHeightV1(IExecutionFrame frame, ulong currentHeight, UInt160 contract, UInt160 caller, ulong gasLimit, InvocationMessage message) { var input = ContractEncoder.Encode(DeployInterface.MethodGetDeployHeight, contract); - var height = DoInternalCall(caller, ContractRegisterer.DeployContract, - input, gasLimit, message).ReturnValue; + UseGas(frame, GasMetering.InvokeContractGasCost * (ulong) VirtualMachine.ExecutionFrames.Count, null); + if (HardforkHeights.IsHardfork_16Active(currentHeight)) + { + gasLimit = frame.GasLimit - frame.GasUsed; + } + var callResult = DoInternalCall( + caller, ContractRegisterer.DeployContract, input, gasLimit, message + ); + var height = callResult.ReturnValue; Logger.LogInformation($"GetDeployHeight result :[{(height != null ? height.ToHex() : "null")}]"); if (HardforkHeights.IsHardfork_6Active(currentHeight)) { @@ -69,16 +76,24 @@ private static ulong GetDeployHeightV1(ulong currentHeight, UInt160 contract, UI if(height.Length < 1) height = HardforkHeights.IsHardfork_8Active(currentHeight) ? HardforkHeights.GetHardfork_3().ToBytes().ToArray() : new byte[64]; } + UseGas(frame, callResult.GasUsed, null); return BitConverter.ToUInt64(height, 0); } - private static ulong GetDeployHeightV2(ulong currentHeight, UInt160 contract, UInt160 caller, ulong gasLimit, InvocationMessage message) + private static ulong GetDeployHeightV2(IExecutionFrame frame, ulong currentHeight, UInt160 contract, UInt160 caller, ulong gasLimit, InvocationMessage message) { try { var input = ContractEncoder.Encode(DeployInterface.MethodGetDeployHeight, contract); - var height = DoInternalCall(caller, ContractRegisterer.DeployContract, - input, gasLimit, message).ReturnValue; + UseGas(frame, GasMetering.InvokeContractGasCost * (ulong) VirtualMachine.ExecutionFrames.Count, null); + if (HardforkHeights.IsHardfork_16Active(currentHeight)) + { + gasLimit = frame.GasLimit - frame.GasUsed; + } + var callResult = DoInternalCall( + caller, ContractRegisterer.DeployContract, input, gasLimit, message + ); + var height = callResult.ReturnValue; Logger.LogInformation($"GetDeployHeight result :[{(height != null ? height.ToHex() : "null")}]"); if (HardforkHeights.IsHardfork_6Active(currentHeight)) { @@ -87,6 +102,7 @@ private static ulong GetDeployHeightV2(ulong currentHeight, UInt160 contract, UI height = HardforkHeights.IsHardfork_8Active(currentHeight) ? HardforkHeights.GetHardfork_3().ToBytes().ToArray() : new byte[64]; } + UseGas(frame, callResult.GasUsed, null); return BitConverter.ToUInt64(height, 0); } catch (Exception ex) @@ -96,10 +112,16 @@ private static ulong GetDeployHeightV2(ulong currentHeight, UInt160 contract, UI } } - private static void SetDeployHeight(UInt160 contract, ulong height, ulong gasLimit, InvocationMessage message) + private static void SetDeployHeight(IExecutionFrame frame, UInt160 contract, ulong height, ulong gasLimit, InvocationMessage message) { var input = ContractEncoder.Encode(DeployInterface.MethodSetDeployHeight, contract, height.ToBytes()); - DoInternalCall(contract, ContractRegisterer.DeployContract, input, gasLimit, message); + UseGas(frame, GasMetering.InvokeContractGasCost * (ulong) VirtualMachine.ExecutionFrames.Count, null); + if (HardforkHeights.IsHardfork_16Active(frame.InvocationContext.Snapshot.Blocks.GetTotalBlockHeight())) + { + gasLimit = frame.GasLimit - frame.GasUsed; + } + var callResult = DoInternalCall(contract, ContractRegisterer.DeployContract, input, gasLimit, message); + UseGas(frame, callResult.GasUsed, null); } private static byte[]? SafeCopyFromMemory(UnmanagedMemory memory, int offset, int length) @@ -150,7 +172,6 @@ private static int InvokeContract( Logger.LogInformation($"InvokeContract({callSignatureOffset}, {inputLength}, {inputOffset}, {valueOffset}, {gasOffset}, {invocationType})"); var frame = VirtualMachine.ExecutionFrames.Peek() as WasmExecutionFrame ?? throw new InvalidOperationException("Cannot call InvokeContract outside wasm frame"); - UseGas(frame, GasMetering.InvokeContractGasCost, null); var snapshot = frame.InvocationContext.Snapshot; var addressBuffer = SafeCopyFromMemory(frame.Memory, callSignatureOffset, 20); var inputBuffer = SafeCopyFromMemory(frame.Memory, inputOffset, inputLength); @@ -186,6 +207,7 @@ private static int InvokeContract( return 0; } + UseGas(frame, GasMetering.InvokeContractGasCost * (ulong) VirtualMachine.ExecutionFrames.Count, null); var gasBuffer = SafeCopyFromMemory(frame.Memory, gasOffset, 8); if (gasBuffer is null) throw new InvalidContractException("Bad call to call function"); @@ -398,10 +420,10 @@ public static int Handler_Env_Create(int valueOffset, int dataOffset, int dataLe Value = frame.InvocationContext.Message?.Value ?? UInt256Utils.Zero, Type = InvocationType.Regular, }; - UseGas(frame, GasMetering.LoadStorageGasCost, null); - var deployHeight = GetDeployHeight(frame.InvocationContext.Snapshot.Blocks.GetTotalBlockHeight(), - frame.CurrentAddress, frame.CurrentAddress, frame.GasLimit, - invocationMessage); + var deployHeight = GetDeployHeight( + frame, frame.InvocationContext.Snapshot.Blocks.GetTotalBlockHeight(), + frame.CurrentAddress, frame.CurrentAddress, frame.GasLimit, invocationMessage + ); if (Hardfork.HardforkHeights.IsHardfork_2Active(deployHeight)) return Handler_Env_Create_V2(valueOffset, dataOffset, dataLength, resultOffset, frame); return Handler_Env_Create_V1(valueOffset, dataOffset, dataLength, resultOffset, frame); @@ -449,9 +471,10 @@ private static int Handler_Env_Create_V1(int valueOffset, int dataOffset, int da Value = frame.InvocationContext.Message?.Value ?? UInt256Utils.Zero, Type = InvocationType.Regular, }; - UseGas(frame, GasMetering.LoadStorageGasCost, null); - var deployHeight = GetDeployHeight(frame.InvocationContext.Snapshot.Blocks.GetTotalBlockHeight(), - frame.CurrentAddress, frame.CurrentAddress, frame.GasLimit, invocationMessage); + var deployHeight = GetDeployHeight( + frame, frame.InvocationContext.Snapshot.Blocks.GetTotalBlockHeight(), + frame.CurrentAddress, frame.CurrentAddress, frame.GasLimit, invocationMessage + ); if (!VirtualMachine.VerifyContract(contract.ByteCode, Hardfork.HardforkHeights.IsHardfork_2Active(deployHeight))) @@ -463,7 +486,7 @@ private static int Handler_Env_Create_V1(int valueOffset, int dataOffset, int da { UseGas(frame, GasMetering.SaveStorageGasCost, null); snapshot.Contracts.AddContract(context.Sender, contract); - SetDeployHeight(hash, deployHeight, frame.GasLimit, invocationMessage); + SetDeployHeight(frame, hash, deployHeight, frame.GasLimit, invocationMessage); } catch (OutOfGasException e) { @@ -542,7 +565,13 @@ private static int Handler_Env_Create_V2(int valueOffset, int dataOffset, int da Value = msgValue, Type = InvocationType.Regular, }; - var status = DoInternalCall(GetHardfork_5CurrentAddressOrDelegate(frame), hash, Array.Empty(), frame.GasLimit, invocationMessage); + UseGas(frame, GasMetering.InvokeContractGasCost * (ulong) VirtualMachine.ExecutionFrames.Count, null); + var gasLimit = frame.GasLimit; + if (HardforkHeights.IsHardfork_16Active(snapshot.Blocks.GetTotalBlockHeight())) + { + gasLimit = frame.GasLimit - frame.GasUsed; + } + var status = DoInternalCall(GetHardfork_5CurrentAddressOrDelegate(frame), hash, Array.Empty(), gasLimit, invocationMessage); if (HardforkHeights.IsHardfork_12Active(frame.InvocationContext.Snapshot.Blocks.GetTotalBlockHeight())) { @@ -558,6 +587,8 @@ private static int Handler_Env_Create_V2(int valueOffset, int dataOffset, int da throw new InvalidContractException("Failed to initialize contract"); } + UseGas(frame, status.GasUsed, null); + // runtime code var runtimeContract = new Contract(hash, status.ReturnValue); @@ -566,15 +597,16 @@ private static int Handler_Env_Create_V2(int valueOffset, int dataOffset, int da throw new InvalidContractException("Failed to verify runtime contract"); } - UseGas(frame, GasMetering.LoadStorageGasCost, null); - var deployHeight = GetDeployHeight(frame.InvocationContext.Snapshot.Blocks.GetTotalBlockHeight(), - context.Sender, context.Sender, frame.GasLimit, invocationMessage); + var deployHeight = GetDeployHeight( + frame, frame.InvocationContext.Snapshot.Blocks.GetTotalBlockHeight(), + context.Sender, context.Sender, frame.GasLimit, invocationMessage + ); try { UseGas(frame, GasMetering.SaveStorageGasCost, null); snapshot.Contracts.AddContract(context.Sender, runtimeContract); - SetDeployHeight(hash, deployHeight, frame.GasLimit, invocationMessage); + SetDeployHeight(frame, hash, deployHeight, frame.GasLimit, invocationMessage); } catch (OutOfGasException e) { @@ -604,9 +636,10 @@ public static int Handler_Env_Create2(int valueOffset, int dataOffset, int dataL Value = frame.InvocationContext.Message?.Value ?? UInt256Utils.Zero, Type = InvocationType.Regular, }; - UseGas(frame, GasMetering.LoadStorageGasCost, null); - var deployHeight = GetDeployHeight(frame.InvocationContext.Snapshot.Blocks.GetTotalBlockHeight(), - frame.CurrentAddress, frame.CurrentAddress, frame.GasLimit, invocationMessage); + var deployHeight = GetDeployHeight( + frame, frame.InvocationContext.Snapshot.Blocks.GetTotalBlockHeight(), + frame.CurrentAddress, frame.CurrentAddress, frame.GasLimit, invocationMessage + ); if (Hardfork.HardforkHeights.IsHardfork_2Active(deployHeight)) return Handler_Env_Create2_V2(valueOffset, dataOffset, dataLength, saltOffset, resultOffset, frame); @@ -654,9 +687,10 @@ public static int Handler_Env_Create2_V1(int valueOffset, int dataOffset, int da Value = frame.InvocationContext.Message?.Value ?? UInt256Utils.Zero, Type = InvocationType.Regular, }; - UseGas(frame, GasMetering.LoadStorageGasCost, null); - var deployHeight = GetDeployHeight(frame.InvocationContext.Snapshot.Blocks.GetTotalBlockHeight(), - frame.CurrentAddress, frame.CurrentAddress, frame.GasLimit, invocationMessage); + var deployHeight = GetDeployHeight( + frame, frame.InvocationContext.Snapshot.Blocks.GetTotalBlockHeight(), + frame.CurrentAddress, frame.CurrentAddress, frame.GasLimit, invocationMessage + ); if (!VirtualMachine.VerifyContract(contract.ByteCode, Hardfork.HardforkHeights.IsHardfork_2Active(deployHeight))) @@ -668,7 +702,7 @@ public static int Handler_Env_Create2_V1(int valueOffset, int dataOffset, int da { UseGas(frame, GasMetering.SaveStorageGasCost, null); snapshot.Contracts.AddContract(context.Sender, contract); - SetDeployHeight(hash, deployHeight, frame.GasLimit, invocationMessage); + SetDeployHeight(frame, hash, deployHeight, frame.GasLimit, invocationMessage); } catch (OutOfGasException e) { @@ -746,7 +780,13 @@ public static int Handler_Env_Create2_V2(int valueOffset, int dataOffset, int da Value = msgValue, Type = InvocationType.Regular, }; - var status = DoInternalCall(GetHardfork_5CurrentAddressOrDelegate(frame), hash, Array.Empty(), frame.GasLimit, invocationMessage); + UseGas(frame, GasMetering.InvokeContractGasCost * (ulong) VirtualMachine.ExecutionFrames.Count, null); + var gasLimit = frame.GasLimit; + if (HardforkHeights.IsHardfork_16Active(snapshot.Blocks.GetTotalBlockHeight())) + { + gasLimit = frame.GasLimit - frame.GasUsed; + } + var status = DoInternalCall(GetHardfork_5CurrentAddressOrDelegate(frame), hash, Array.Empty(), gasLimit, invocationMessage); if (HardforkHeights.IsHardfork_12Active(frame.InvocationContext.Snapshot.Blocks.GetTotalBlockHeight())) { @@ -762,12 +802,15 @@ public static int Handler_Env_Create2_V2(int valueOffset, int dataOffset, int da throw new InvalidContractException("Failed to initialize contract"); } + UseGas(frame, status.GasUsed, null); + // runtime code var runtimeContract = new Contract(hash, status.ReturnValue); - UseGas(frame, GasMetering.LoadStorageGasCost, null); - var deployHeight = GetDeployHeight(frame.InvocationContext.Snapshot.Blocks.GetTotalBlockHeight(), - frame.CurrentAddress, frame.CurrentAddress, frame.GasLimit, invocationMessage); + var deployHeight = GetDeployHeight( + frame, frame.InvocationContext.Snapshot.Blocks.GetTotalBlockHeight(), + frame.CurrentAddress, frame.CurrentAddress, frame.GasLimit, invocationMessage + ); if (!VirtualMachine.VerifyContract(runtimeContract.ByteCode, true)) { @@ -778,7 +821,7 @@ public static int Handler_Env_Create2_V2(int valueOffset, int dataOffset, int da { UseGas(frame, GasMetering.SaveStorageGasCost, null); snapshot.Contracts.AddContract(context.Sender, runtimeContract); - SetDeployHeight(hash, deployHeight, frame.GasLimit, invocationMessage); + SetDeployHeight(frame, hash, deployHeight, frame.GasLimit, invocationMessage); } catch (OutOfGasException e) { diff --git a/src/Lachain.Core/Blockchain/VM/GasMetering.cs b/src/Lachain.Core/Blockchain/VM/GasMetering.cs index caf4e60a0..159b90540 100644 --- a/src/Lachain.Core/Blockchain/VM/GasMetering.cs +++ b/src/Lachain.Core/Blockchain/VM/GasMetering.cs @@ -18,7 +18,7 @@ public class GasMetering public const ulong GetGasLeftGasCost = 100; public const ulong CopyCodeValueGasCost = 100; public const ulong GetCodeSizeGasCost = 10; - public const ulong InvokeContractGasCost = 7_000_000; + public const ulong InvokeContractGasCost = 200_000; public const ulong TransferFundsGasCost = 3_000_000; public const ulong LoadStorageGasCost = 500_000; public const ulong SaveStorageGasCost = 3_000_000; From 5d86ddcdf6c53bbf949911a1a70ec0dcbc0ce049 Mon Sep 17 00:00:00 2001 From: tbssajal Date: Fri, 20 Jan 2023 23:00:16 +0600 Subject: [PATCH 12/16] fixed bug --- src/Lachain.Core/Blockchain/Operations/BlockManager.cs | 1 + 1 file changed, 1 insertion(+) diff --git a/src/Lachain.Core/Blockchain/Operations/BlockManager.cs b/src/Lachain.Core/Blockchain/Operations/BlockManager.cs index 456742437..690b5d407 100644 --- a/src/Lachain.Core/Blockchain/Operations/BlockManager.cs +++ b/src/Lachain.Core/Blockchain/Operations/BlockManager.cs @@ -511,6 +511,7 @@ out Money totalFee throw new InvalidBlockException(OperatingError.BlockGasOverflow); Logger.LogWarning( $"Unable to take transaction {txHash.ToHex()} with gas {receipt.GasUsed}, block gas limit overflowed {gasUsed}/{GasMetering.DefaultBlockGasLimit}"); + gasUsed -= receipt.GasUsed; continue; } else Logger.LogInformation($"Block gas limit after execution ok for tx : {txHash.ToHex()}"); From 967b31fb6bc101342e96e3ebf6723c1977b77d14 Mon Sep 17 00:00:00 2001 From: tbssajal Date: Mon, 23 Jan 2023 16:27:00 +0600 Subject: [PATCH 13/16] fixed bug --- src/Lachain.Core/Blockchain/VM/ExternalHandler.cs | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/src/Lachain.Core/Blockchain/VM/ExternalHandler.cs b/src/Lachain.Core/Blockchain/VM/ExternalHandler.cs index cbe92b9bc..028e28dc4 100644 --- a/src/Lachain.Core/Blockchain/VM/ExternalHandler.cs +++ b/src/Lachain.Core/Blockchain/VM/ExternalHandler.cs @@ -68,6 +68,7 @@ private static ulong GetDeployHeightV1(IExecutionFrame frame, ulong currentHeigh var callResult = DoInternalCall( caller, ContractRegisterer.DeployContract, input, gasLimit, message ); + UseGas(frame, callResult.GasUsed, null); var height = callResult.ReturnValue; Logger.LogInformation($"GetDeployHeight result :[{(height != null ? height.ToHex() : "null")}]"); if (HardforkHeights.IsHardfork_6Active(currentHeight)) @@ -76,7 +77,6 @@ private static ulong GetDeployHeightV1(IExecutionFrame frame, ulong currentHeigh if(height.Length < 1) height = HardforkHeights.IsHardfork_8Active(currentHeight) ? HardforkHeights.GetHardfork_3().ToBytes().ToArray() : new byte[64]; } - UseGas(frame, callResult.GasUsed, null); return BitConverter.ToUInt64(height, 0); } @@ -93,6 +93,7 @@ private static ulong GetDeployHeightV2(IExecutionFrame frame, ulong currentHeigh var callResult = DoInternalCall( caller, ContractRegisterer.DeployContract, input, gasLimit, message ); + UseGas(frame, callResult.GasUsed, null); var height = callResult.ReturnValue; Logger.LogInformation($"GetDeployHeight result :[{(height != null ? height.ToHex() : "null")}]"); if (HardforkHeights.IsHardfork_6Active(currentHeight)) @@ -102,7 +103,6 @@ private static ulong GetDeployHeightV2(IExecutionFrame frame, ulong currentHeigh height = HardforkHeights.IsHardfork_8Active(currentHeight) ? HardforkHeights.GetHardfork_3().ToBytes().ToArray() : new byte[64]; } - UseGas(frame, callResult.GasUsed, null); return BitConverter.ToUInt64(height, 0); } catch (Exception ex) @@ -237,6 +237,8 @@ private static int InvokeContract( } Logger.LogInformation($"invocationMessage.Sender: {invocationMessage.Sender.ToHex()}"); var callResult = DoInternalCall(GetHardfork_5CurrentAddressOrDelegate(frame), address, inputBuffer, gasLimit, invocationMessage); + UseGas(frame, callResult.GasUsed, null); + if (HardforkHeights.IsHardfork_12Active(frame.InvocationContext.Snapshot.Blocks.GetTotalBlockHeight())) { @@ -252,7 +254,7 @@ private static int InvokeContract( throw new InvalidContractException($"Cannot invoke call: {callResult.Status}, {callResult.ReturnValue}"); } - frame.UseGas(callResult.GasUsed); + UseGas(frame, null, callResult.GasUsed); frame.LastChildReturnValue = callResult.ReturnValue ?? Array.Empty(); return 0; } @@ -572,6 +574,7 @@ private static int Handler_Env_Create_V2(int valueOffset, int dataOffset, int da gasLimit = frame.GasLimit - frame.GasUsed; } var status = DoInternalCall(GetHardfork_5CurrentAddressOrDelegate(frame), hash, Array.Empty(), gasLimit, invocationMessage); + UseGas(frame, status.GasUsed, null); if (HardforkHeights.IsHardfork_12Active(frame.InvocationContext.Snapshot.Blocks.GetTotalBlockHeight())) { @@ -587,8 +590,6 @@ private static int Handler_Env_Create_V2(int valueOffset, int dataOffset, int da throw new InvalidContractException("Failed to initialize contract"); } - UseGas(frame, status.GasUsed, null); - // runtime code var runtimeContract = new Contract(hash, status.ReturnValue); @@ -787,6 +788,7 @@ public static int Handler_Env_Create2_V2(int valueOffset, int dataOffset, int da gasLimit = frame.GasLimit - frame.GasUsed; } var status = DoInternalCall(GetHardfork_5CurrentAddressOrDelegate(frame), hash, Array.Empty(), gasLimit, invocationMessage); + UseGas(frame, status.GasUsed, null); if (HardforkHeights.IsHardfork_12Active(frame.InvocationContext.Snapshot.Blocks.GetTotalBlockHeight())) { @@ -802,8 +804,6 @@ public static int Handler_Env_Create2_V2(int valueOffset, int dataOffset, int da throw new InvalidContractException("Failed to initialize contract"); } - UseGas(frame, status.GasUsed, null); - // runtime code var runtimeContract = new Contract(hash, status.ReturnValue); From c945737ea07d0cf01e2ebaa9c8693349f574b6ea Mon Sep 17 00:00:00 2001 From: tbssajal Date: Mon, 23 Jan 2023 22:56:16 +0600 Subject: [PATCH 14/16] fixed tests --- .../RPC/HTTP/Web3/Web3TransactionTests.cs | 65 +++++++++++-------- test/Lachain.CoreTest/Resources/config2.json | 3 +- 2 files changed, 40 insertions(+), 28 deletions(-) diff --git a/test/Lachain.CoreTest/RPC/HTTP/Web3/Web3TransactionTests.cs b/test/Lachain.CoreTest/RPC/HTTP/Web3/Web3TransactionTests.cs index 67b2273d2..957beb378 100644 --- a/test/Lachain.CoreTest/RPC/HTTP/Web3/Web3TransactionTests.cs +++ b/test/Lachain.CoreTest/RPC/HTTP/Web3/Web3TransactionTests.cs @@ -336,10 +336,43 @@ public void Test_EstimateGas() { _blockManager.TryBuildGenesisBlock(); - var keyPair = _privateWallet!.EcdsaKeyPair; - GenerateBlocks(1, 1); + + DeployAndTestContract("0x2e1d22"); + + // after hardfork: + while (!HardforkHeights.IsHardfork_16Active(_blockManager.GetHeight())) + GenerateBlocks(_blockManager.GetHeight() + 1, _blockManager.GetHeight() + 1); + + DeployAndTestContract("0x2e356e"); + + var receipt = TestUtils.GetRandomTransaction(false); + var opts = new JObject + { + ["from"] = receipt.Transaction.From.ToHex(), + ["to"] = receipt.Transaction.To.ToHex(), + }; + + var result = _apiService!.EstimateGas(opts); + Assert.AreNotEqual(result, "0x"); + } + + [Test] + /// Changed from private to public + [Ignore("fix it")] + public void Test_GetNetworkGasPrice() + { + var gasPrice_Expected = "0x1"; + + var gasPrice_Actual = _apiService!.GetNetworkGasPrice(); + + Assert.AreEqual(gasPrice_Expected, gasPrice_Actual); + } + + private void DeployAndTestContract(string gasEstimate) + { // Deploy contract + var keyPair = _privateWallet!.EcdsaKeyPair; var byteCode = ByteCodeHex.HexToBytes(); Assert.That(VirtualMachine.VerifyContract(byteCode, true), "Unable to validate smart-contract code"); var from = keyPair.PublicKey.GetAddress(); @@ -352,7 +385,7 @@ public void Test_EstimateGas() var tx = _transactionBuilder.DeployTransaction(from, byteCode); var signedTx = _transactionSigner.Sign(tx, keyPair, HardforkHeights.IsHardfork_9Active(2)); Assert.That(_transactionPool.Add(signedTx) == OperatingError.Ok, "Can't add deploy tx to pool"); - GenerateBlocks(2, 2); + GenerateBlocks(_blockManager.GetHeight() + 1, _blockManager.GetHeight() + 1); // check contract is deployed var contract = _stateManager.LastApprovedSnapshot.Contracts.GetContractByHash(contractHash); @@ -369,30 +402,8 @@ public void Test_EstimateGas() }; var result = _apiService!.EstimateGas(opts); - Assert.AreEqual(result, "0x2eae18"); - - var receipt = TestUtils.GetRandomTransaction(false); - opts = new JObject - { - ["from"] = receipt.Transaction.From.ToHex(), - ["to"] = receipt.Transaction.To.ToHex(), - }; - - result = _apiService!.EstimateGas(opts); - Assert.AreNotEqual(result, "0x"); - } - - [Test] - /// Changed from private to public - [Ignore("fix it")] - public void Test_GetNetworkGasPrice() - { - var gasPrice_Expected = "0x1"; - - var gasPrice_Actual = _apiService!.GetNetworkGasPrice(); - - Assert.AreEqual(gasPrice_Expected, gasPrice_Actual); - + System.Console.WriteLine(HardforkHeights.IsHardfork_16Active(_blockManager.GetHeight())); + Assert.AreEqual(result, gasEstimate); } // Below methods Execute a Transaction diff --git a/test/Lachain.CoreTest/Resources/config2.json b/test/Lachain.CoreTest/Resources/config2.json index e9ad640eb..6344d869f 100644 --- a/test/Lachain.CoreTest/Resources/config2.json +++ b/test/Lachain.CoreTest/Resources/config2.json @@ -58,7 +58,8 @@ "hardfork_12": 0, "hardfork_13": 0, "hardfork_14": 0, - "hardfork_15": 0 + "hardfork_15": 0, + "hardfork_16": 10 }, "storage": { "provider": "RocksDB", From 33f295d176f4b910a5e599d15b91ec40c470e36a Mon Sep 17 00:00:00 2001 From: tbssajal Date: Mon, 23 Jan 2023 23:41:28 +0600 Subject: [PATCH 15/16] fixed test --- test/Lachain.CoreTest/RPC/HTTP/Web3/Web3TransactionTests.cs | 2 -- 1 file changed, 2 deletions(-) diff --git a/test/Lachain.CoreTest/RPC/HTTP/Web3/Web3TransactionTests.cs b/test/Lachain.CoreTest/RPC/HTTP/Web3/Web3TransactionTests.cs index 957beb378..689cd0d98 100644 --- a/test/Lachain.CoreTest/RPC/HTTP/Web3/Web3TransactionTests.cs +++ b/test/Lachain.CoreTest/RPC/HTTP/Web3/Web3TransactionTests.cs @@ -337,8 +337,6 @@ public void Test_EstimateGas() _blockManager.TryBuildGenesisBlock(); - DeployAndTestContract("0x2e1d22"); - // after hardfork: while (!HardforkHeights.IsHardfork_16Active(_blockManager.GetHeight())) GenerateBlocks(_blockManager.GetHeight() + 1, _blockManager.GetHeight() + 1); From d967acf53cc7307d4c4f6a530a824e685b31935a Mon Sep 17 00:00:00 2001 From: tbssajal Date: Wed, 25 Jan 2023 21:59:51 +0600 Subject: [PATCH 16/16] removed duplicate method --- src/Lachain.Core/Blockchain/Hardfork/HardforkHeights.cs | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/src/Lachain.Core/Blockchain/Hardfork/HardforkHeights.cs b/src/Lachain.Core/Blockchain/Hardfork/HardforkHeights.cs index 2621e1c7b..188038285 100644 --- a/src/Lachain.Core/Blockchain/Hardfork/HardforkHeights.cs +++ b/src/Lachain.Core/Blockchain/Hardfork/HardforkHeights.cs @@ -104,12 +104,8 @@ public static bool IsHardfork_15Active(ulong height) return height >= Hardfork_15; } - public static bool IsHardfork_16Active(ulong height) - { - return height >= Hardfork_16; - } - // adjust gas consumption + // allow contract balance transfer in ExternalHandler.cs public static bool IsHardfork_16Active(ulong height) { return height >= Hardfork_16;