diff --git a/src/neo/SmartContract/ApplicationEngine.cs b/src/neo/SmartContract/ApplicationEngine.cs index 53bc8c68a8..500e75a6b5 100644 --- a/src/neo/SmartContract/ApplicationEngine.cs +++ b/src/neo/SmartContract/ApplicationEngine.cs @@ -25,6 +25,7 @@ public partial class ApplicationEngine : ExecutionEngine public IVerifiable ScriptContainer { get; } public StoreView Snapshot { get; } public long GasConsumed { get; private set; } = 0; + public UInt160 CurrentScriptHash => CurrentContext?.GetState().ScriptHash; public UInt160 CallingScriptHash => CurrentContext?.GetState().CallingScriptHash; public UInt160 EntryScriptHash => EntryContext?.GetState().ScriptHash; @@ -78,7 +79,7 @@ public override void Dispose() protected override bool OnSysCall(uint method) { - if (!AddGas(InteropService.GetPrice(method, CurrentContext.EvaluationStack))) + if (!AddGas(InteropService.GetPrice(method, CurrentContext.EvaluationStack, Snapshot))) return false; return InteropService.Invoke(this, method); } diff --git a/src/neo/SmartContract/InteropDescriptor.cs b/src/neo/SmartContract/InteropDescriptor.cs index 6984eba13c..ebc94c2f3e 100644 --- a/src/neo/SmartContract/InteropDescriptor.cs +++ b/src/neo/SmartContract/InteropDescriptor.cs @@ -1,3 +1,4 @@ +using Neo.Persistence; using Neo.VM; using System; @@ -9,7 +10,7 @@ public class InteropDescriptor public uint Hash { get; } internal Func Handler { get; } public long Price { get; } - public Func PriceCalculator { get; } + public Func PriceCalculator { get; } public TriggerType AllowedTriggers { get; } public CallFlags RequiredCallFlags { get; } @@ -19,7 +20,7 @@ internal InteropDescriptor(string method, Func handler, this.Price = price; } - internal InteropDescriptor(string method, Func handler, Func priceCalculator, TriggerType allowedTriggers, CallFlags requiredCallFlags) + internal InteropDescriptor(string method, Func handler, Func priceCalculator, TriggerType allowedTriggers, CallFlags requiredCallFlags) : this(method, handler, allowedTriggers, requiredCallFlags) { this.PriceCalculator = priceCalculator; @@ -34,9 +35,9 @@ private InteropDescriptor(string method, Func handler, this.RequiredCallFlags = requiredCallFlags; } - public long GetPrice(EvaluationStack stack) + public long GetPrice(EvaluationStack stack, StoreView snapshot) { - return PriceCalculator is null ? Price : PriceCalculator(stack); + return PriceCalculator is null ? Price : PriceCalculator(stack, snapshot); } public static implicit operator uint(InteropDescriptor descriptor) diff --git a/src/neo/SmartContract/InteropService.Contract.cs b/src/neo/SmartContract/InteropService.Contract.cs index 14823db8c8..b6cd2862b7 100644 --- a/src/neo/SmartContract/InteropService.Contract.cs +++ b/src/neo/SmartContract/InteropService.Contract.cs @@ -1,5 +1,6 @@ using Neo.IO; using Neo.Ledger; +using Neo.Persistence; using Neo.SmartContract.Manifest; using Neo.VM; using Neo.VM.Types; @@ -19,7 +20,7 @@ public static class Contract public static readonly InteropDescriptor CallEx = Register("System.Contract.CallEx", Contract_CallEx, 0_01000000, TriggerType.System | TriggerType.Application, CallFlags.AllowCall); public static readonly InteropDescriptor IsStandard = Register("System.Contract.IsStandard", Contract_IsStandard, 0_00030000, TriggerType.All, CallFlags.None); - private static long GetDeploymentPrice(EvaluationStack stack) + private static long GetDeploymentPrice(EvaluationStack stack, StoreView snapshot) { int size = stack.Peek(0).GetByteLength() + stack.Peek(1).GetByteLength(); return Storage.GasPerByte * size; diff --git a/src/neo/SmartContract/InteropService.Crypto.cs b/src/neo/SmartContract/InteropService.Crypto.cs index 448d312ea4..9678f321ce 100644 --- a/src/neo/SmartContract/InteropService.Crypto.cs +++ b/src/neo/SmartContract/InteropService.Crypto.cs @@ -1,6 +1,7 @@ using Neo.Cryptography; using Neo.Network.P2P; using Neo.Network.P2P.Payloads; +using Neo.Persistence; using Neo.VM; using Neo.VM.Types; using System; @@ -16,7 +17,7 @@ public static class Crypto public static readonly InteropDescriptor ECDsaVerify = Register("Neo.Crypto.ECDsaVerify", Crypto_ECDsaVerify, 0_01000000, TriggerType.All, CallFlags.None); public static readonly InteropDescriptor ECDsaCheckMultiSig = Register("Neo.Crypto.ECDsaCheckMultiSig", Crypto_ECDsaCheckMultiSig, GetECDsaCheckMultiSigPrice, TriggerType.All, CallFlags.None); - private static long GetECDsaCheckMultiSigPrice(EvaluationStack stack) + private static long GetECDsaCheckMultiSigPrice(EvaluationStack stack, StoreView snapshot) { if (stack.Count < 2) return 0; var item = stack.Peek(1); diff --git a/src/neo/SmartContract/InteropService.Storage.cs b/src/neo/SmartContract/InteropService.Storage.cs index 3355a5f83c..a9fc9e9303 100644 --- a/src/neo/SmartContract/InteropService.Storage.cs +++ b/src/neo/SmartContract/InteropService.Storage.cs @@ -1,4 +1,5 @@ using Neo.Ledger; +using Neo.Persistence; using Neo.SmartContract.Iterators; using Neo.VM; using Neo.VM.Types; @@ -22,11 +23,30 @@ public static class Storage public static readonly InteropDescriptor Find = Register("System.Storage.Find", Storage_Find, 0_01000000, TriggerType.Application, CallFlags.None); public static readonly InteropDescriptor Put = Register("System.Storage.Put", Storage_Put, GetStoragePrice, TriggerType.Application, CallFlags.AllowModifyStates); public static readonly InteropDescriptor PutEx = Register("System.Storage.PutEx", Storage_PutEx, GetStoragePrice, TriggerType.Application, CallFlags.AllowModifyStates); - public static readonly InteropDescriptor Delete = Register("System.Storage.Delete", Storage_Delete, 0_01000000, TriggerType.Application, CallFlags.AllowModifyStates); + public static readonly InteropDescriptor Delete = Register("System.Storage.Delete", Storage_Delete, 1 * GasPerByte, TriggerType.Application, CallFlags.AllowModifyStates); - private static long GetStoragePrice(EvaluationStack stack) + private static long GetStoragePrice(EvaluationStack stack, StoreView snapshot) { - return (stack.Peek(1).GetByteLength() + stack.Peek(2).GetByteLength()) * GasPerByte; + var key = stack.Peek(1); + var value = stack.Peek(2); + var newDataSize = value.IsNull ? 0 : value.GetByteLength(); + if (!(stack.Peek() is InteropInterface _interface)) + throw new InvalidOperationException(); + + StorageContext context = _interface.GetInterface(); + StorageKey skey = new StorageKey + { + Id = context.Id, + Key = key.GetSpan().ToArray() + }; + var skeyValue = snapshot.Storages.TryGet(skey); + if (skeyValue is null) + newDataSize += key.GetByteLength(); + else if (newDataSize <= skeyValue.Value.Length) + newDataSize = 1; + else + newDataSize -= skeyValue.Value.Length; + return newDataSize * GasPerByte; } private static bool PutExInternal(ApplicationEngine engine, StorageContext context, byte[] key, byte[] value, StorageFlags flags) diff --git a/src/neo/SmartContract/InteropService.cs b/src/neo/SmartContract/InteropService.cs index c87ad277ea..f2a673c82f 100644 --- a/src/neo/SmartContract/InteropService.cs +++ b/src/neo/SmartContract/InteropService.cs @@ -1,3 +1,4 @@ +using Neo.Persistence; using Neo.VM; using System; using System.Collections.Generic; @@ -15,9 +16,9 @@ static InteropService() t.GetFields()[0].GetValue(null); } - public static long GetPrice(uint hash, EvaluationStack stack) + public static long GetPrice(uint hash, EvaluationStack stack, StoreView snapshot) { - return methods[hash].GetPrice(stack); + return methods[hash].GetPrice(stack, snapshot); } public static IEnumerable SupportedMethods() @@ -44,7 +45,7 @@ private static InteropDescriptor Register(string method, Func handler, Func priceCalculator, TriggerType allowedTriggers, CallFlags requiredCallFlags) + private static InteropDescriptor Register(string method, Func handler, Func priceCalculator, TriggerType allowedTriggers, CallFlags requiredCallFlags) { InteropDescriptor descriptor = new InteropDescriptor(method, handler, priceCalculator, allowedTriggers, requiredCallFlags); methods.Add(descriptor.Hash, descriptor); diff --git a/src/neo/SmartContract/Native/NativeContract.cs b/src/neo/SmartContract/Native/NativeContract.cs index b7c7f85251..b28f55be14 100644 --- a/src/neo/SmartContract/Native/NativeContract.cs +++ b/src/neo/SmartContract/Native/NativeContract.cs @@ -2,6 +2,7 @@ using Neo.IO; using Neo.Ledger; +using Neo.Persistence; using Neo.SmartContract.Manifest; using Neo.SmartContract.Native.Tokens; using Neo.VM; @@ -101,7 +102,7 @@ internal bool Invoke(ApplicationEngine engine) return true; } - internal long GetPrice(EvaluationStack stack) + internal long GetPrice(EvaluationStack stack, StoreView snapshot) { return methods.TryGetValue(stack.Peek().GetString(), out ContractMethodMetadata method) ? method.Price : 0; } diff --git a/src/neo/Wallets/Wallet.cs b/src/neo/Wallets/Wallet.cs index 3fe4c61652..c0bf012c2a 100644 --- a/src/neo/Wallets/Wallet.cs +++ b/src/neo/Wallets/Wallet.cs @@ -354,7 +354,7 @@ public static long CalculateNetworkFee(byte[] witness_script, ref int size) if (witness_script.IsSignatureContract()) { size += 67 + witness_script.GetVarSize(); - networkFee += ApplicationEngine.OpCodePrices[OpCode.PUSHDATA1] + ApplicationEngine.OpCodePrices[OpCode.PUSHDATA1] + ApplicationEngine.OpCodePrices[OpCode.PUSHNULL] + InteropService.GetPrice(InteropService.Crypto.ECDsaVerify, null); + networkFee += ApplicationEngine.OpCodePrices[OpCode.PUSHDATA1] + ApplicationEngine.OpCodePrices[OpCode.PUSHDATA1] + ApplicationEngine.OpCodePrices[OpCode.PUSHNULL] + InteropService.GetPrice(InteropService.Crypto.ECDsaVerify, null, null); } else if (witness_script.IsMultiSigContract(out int m, out int n)) { @@ -366,7 +366,7 @@ public static long CalculateNetworkFee(byte[] witness_script, ref int size) networkFee += ApplicationEngine.OpCodePrices[OpCode.PUSHDATA1] * n; using (ScriptBuilder sb = new ScriptBuilder()) networkFee += ApplicationEngine.OpCodePrices[(OpCode)sb.EmitPush(n).ToArray()[0]]; - networkFee += ApplicationEngine.OpCodePrices[OpCode.PUSHNULL] + InteropService.GetPrice(InteropService.Crypto.ECDsaVerify, null) * n; + networkFee += ApplicationEngine.OpCodePrices[OpCode.PUSHNULL] + InteropService.GetPrice(InteropService.Crypto.ECDsaVerify, null, null) * n; } else { diff --git a/tests/neo.UnitTests/SmartContract/UT_InteropPrices.cs b/tests/neo.UnitTests/SmartContract/UT_InteropPrices.cs index 19eb7a5d38..e34c80eb96 100644 --- a/tests/neo.UnitTests/SmartContract/UT_InteropPrices.cs +++ b/tests/neo.UnitTests/SmartContract/UT_InteropPrices.cs @@ -1,13 +1,22 @@ using FluentAssertions; using Microsoft.VisualStudio.TestTools.UnitTesting; +using Neo.Ledger; using Neo.SmartContract; +using Neo.SmartContract.Manifest; using Neo.VM; +using System; namespace Neo.UnitTests.SmartContract { [TestClass] public class UT_InteropPrices { + [TestInitialize] + public void Initialize() + { + TestBlockchain.InitializeMockNeoSystem(); + } + [TestMethod] public void ApplicationEngineFixedPrices() { @@ -16,7 +25,7 @@ public void ApplicationEngineFixedPrices() using (ApplicationEngine ae = new ApplicationEngine(TriggerType.Application, null, null, 0)) { ae.LoadScript(SyscallSystemRuntimeCheckWitnessHash); - InteropService.GetPrice(InteropService.Runtime.CheckWitness, ae.CurrentContext.EvaluationStack).Should().Be(0_00030000L); + InteropService.GetPrice(InteropService.Runtime.CheckWitness, ae.CurrentContext.EvaluationStack, ae.Snapshot).Should().Be(0_00030000L); } // System.Storage.GetContext: 9bf667ce (price is 1) @@ -24,7 +33,7 @@ public void ApplicationEngineFixedPrices() using (ApplicationEngine ae = new ApplicationEngine(TriggerType.Application, null, null, 0)) { ae.LoadScript(SyscallSystemStorageGetContextHash); - InteropService.GetPrice(InteropService.Storage.GetContext, ae.CurrentContext.EvaluationStack).Should().Be(0_00000400L); + InteropService.GetPrice(InteropService.Storage.GetContext, ae.CurrentContext.EvaluationStack, ae.Snapshot).Should().Be(0_00000400L); } // System.Storage.Get: 925de831 (price is 100) @@ -32,7 +41,7 @@ public void ApplicationEngineFixedPrices() using (ApplicationEngine ae = new ApplicationEngine(TriggerType.Application, null, null, 0)) { ae.LoadScript(SyscallSystemStorageGetHash); - InteropService.GetPrice(InteropService.Storage.Get, ae.CurrentContext.EvaluationStack).Should().Be(0_01000000L); + InteropService.GetPrice(InteropService.Storage.Get, ae.CurrentContext.EvaluationStack, ae.Snapshot).Should().Be(0_01000000L); } } @@ -47,7 +56,7 @@ public void ApplicationEngineVariablePrices() ae.LoadScript(SyscallContractCreateHash00); debugger.StepInto(); // PUSHDATA1 debugger.StepInto(); // PUSHDATA1 - InteropService.GetPrice(InteropService.Contract.Create, ae.CurrentContext.EvaluationStack).Should().Be(0_00300000L); + InteropService.GetPrice(InteropService.Contract.Create, ae.CurrentContext.EvaluationStack, ae.Snapshot).Should().Be(0_00300000L); } // System.Storage.Put: e63f1884 (requires push key and value) @@ -59,7 +68,8 @@ public void ApplicationEngineVariablePrices() debugger.StepInto(); // push 03 (length 1) debugger.StepInto(); // push 03 (length 1) debugger.StepInto(); // push 00 - InteropService.GetPrice(InteropService.Storage.Put, ae.CurrentContext.EvaluationStack).Should().Be(200000L); + Action act = () => InteropService.GetPrice(InteropService.Storage.Put, ae.CurrentContext.EvaluationStack, ae.Snapshot); + act.Should().Throw(); } // System.Storage.PutEx: 73e19b3a (requires push key and value) @@ -71,8 +81,192 @@ public void ApplicationEngineVariablePrices() debugger.StepInto(); // push 03 (length 1) debugger.StepInto(); // push 03 (length 1) debugger.StepInto(); // push 00 - InteropService.GetPrice(InteropService.Storage.PutEx, ae.CurrentContext.EvaluationStack).Should().Be(200000L); + Action act = () => InteropService.GetPrice(InteropService.Storage.Put, ae.CurrentContext.EvaluationStack, ae.Snapshot); + act.Should().Throw(); + } + } + + /// + /// Put without previous content (should charge per byte used) + /// + [TestMethod] + public void ApplicationEngineRegularPut() + { + var key = new byte[] { (byte)OpCode.PUSH1 }; + var value = new byte[] { (byte)OpCode.PUSH1 }; + + byte[] script = CreatePutScript(key, value); + + ContractState contractState = TestUtils.GetContract(script); + contractState.Manifest.Features = ContractFeatures.HasStorage; + + StorageKey skey = TestUtils.GetStorageKey(contractState.Id, key); + StorageItem sItem = TestUtils.GetStorageItem(new byte[0] { }); + + var snapshot = Blockchain.Singleton.GetSnapshot(); + snapshot.Storages.Add(skey, sItem); + snapshot.Contracts.Add(script.ToScriptHash(), contractState); + + using (ApplicationEngine ae = new ApplicationEngine(TriggerType.Application, null, snapshot, 0, testMode: true)) + { + Debugger debugger = new Debugger(ae); + ae.LoadScript(script); + debugger.StepInto(); + debugger.StepInto(); + debugger.StepInto(); + var setupPrice = ae.GasConsumed; + var defaultDataPrice = InteropService.GetPrice(InteropService.Storage.Put, ae.CurrentContext.EvaluationStack, ae.Snapshot); + defaultDataPrice.Should().Be(InteropService.Storage.GasPerByte * value.Length); + var expectedCost = defaultDataPrice + setupPrice; + debugger.Execute(); + ae.GasConsumed.Should().Be(expectedCost); } } + + /// + /// Reuses the same amount of storage. Should cost 0. + /// + [TestMethod] + public void ApplicationEngineReusedStorage_FullReuse() + { + var key = new byte[] { (byte)OpCode.PUSH1 }; + var value = new byte[] { (byte)OpCode.PUSH1 }; + + byte[] script = CreatePutScript(key, value); + + ContractState contractState = TestUtils.GetContract(script); + contractState.Manifest.Features = ContractFeatures.HasStorage; + + StorageKey skey = TestUtils.GetStorageKey(contractState.Id, key); + StorageItem sItem = TestUtils.GetStorageItem(value); + + var snapshot = Blockchain.Singleton.GetSnapshot(); + snapshot.Storages.Add(skey, sItem); + snapshot.Contracts.Add(script.ToScriptHash(), contractState); + + using (ApplicationEngine applicationEngine = new ApplicationEngine(TriggerType.Application, null, snapshot, 0, testMode: true)) + { + Debugger debugger = new Debugger(applicationEngine); + applicationEngine.LoadScript(script); + debugger.StepInto(); + debugger.StepInto(); + debugger.StepInto(); + var setupPrice = applicationEngine.GasConsumed; + var reusedDataPrice = InteropService.GetPrice(InteropService.Storage.Put, applicationEngine.CurrentContext.EvaluationStack, applicationEngine.Snapshot); + reusedDataPrice.Should().Be(1 * InteropService.Storage.GasPerByte); + debugger.Execute(); + var expectedCost = reusedDataPrice + setupPrice; + applicationEngine.GasConsumed.Should().Be(expectedCost); + } + } + + /// + /// Reuses one byte and allocates a new one + /// It should only pay for the second byte. + /// + [TestMethod] + public void ApplicationEngineReusedStorage_PartialReuse() + { + var key = new byte[] { (byte)OpCode.PUSH1 }; + var oldValue = new byte[] { (byte)OpCode.PUSH1 }; + var value = new byte[] { (byte)OpCode.PUSH1, (byte)OpCode.PUSH1 }; + + byte[] script = CreatePutScript(key, value); + + ContractState contractState = TestUtils.GetContract(script); + contractState.Manifest.Features = ContractFeatures.HasStorage; + + StorageKey skey = TestUtils.GetStorageKey(contractState.Id, key); + StorageItem sItem = TestUtils.GetStorageItem(oldValue); + + var snapshot = Blockchain.Singleton.GetSnapshot(); + snapshot.Storages.Add(skey, sItem); + snapshot.Contracts.Add(script.ToScriptHash(), contractState); + + using (ApplicationEngine ae = new ApplicationEngine(TriggerType.Application, null, snapshot, 0, testMode: true)) + { + Debugger debugger = new Debugger(ae); + ae.LoadScript(script); + debugger.StepInto(); + debugger.StepInto(); + debugger.StepInto(); + var setupPrice = ae.GasConsumed; + var reusedDataPrice = InteropService.GetPrice(InteropService.Storage.Put, ae.CurrentContext.EvaluationStack, ae.Snapshot); + reusedDataPrice.Should().Be(1 * InteropService.Storage.GasPerByte); + debugger.StepInto(); + var expectedCost = reusedDataPrice + setupPrice; + debugger.StepInto(); + ae.GasConsumed.Should().Be(expectedCost); + } + } + + /// + /// Use put for the same key twice. + /// Pays for 1 extra byte for the first Put and 1 byte for the second basic fee (as value2.length == value1.length). + /// + [TestMethod] + public void ApplicationEngineReusedStorage_PartialReuseTwice() + { + var key = new byte[] { (byte)OpCode.PUSH1 }; + var oldValue = new byte[] { (byte)OpCode.PUSH1 }; + var value = new byte[] { (byte)OpCode.PUSH1, (byte)OpCode.PUSH1 }; + + byte[] script = CreateMultiplePutScript(key, value); + + ContractState contractState = TestUtils.GetContract(script); + contractState.Manifest.Features = ContractFeatures.HasStorage; + + StorageKey skey = TestUtils.GetStorageKey(contractState.Id, key); + StorageItem sItem = TestUtils.GetStorageItem(oldValue); + + var snapshot = Blockchain.Singleton.GetSnapshot(); + snapshot.Storages.Add(skey, sItem); + snapshot.Contracts.Add(script.ToScriptHash(), contractState); + + using (ApplicationEngine ae = new ApplicationEngine(TriggerType.Application, null, snapshot, 0, testMode: true)) + { + Debugger debugger = new Debugger(ae); + ae.LoadScript(script); + debugger.StepInto(); //push key + debugger.StepInto(); //push value + debugger.StepInto(); //syscall Storage.GetContext + var setupPrice = ae.GasConsumed; + var incrementDataPrice = InteropService.GetPrice(InteropService.Storage.Put, ae.CurrentContext.EvaluationStack, ae.Snapshot); + incrementDataPrice.Should().Be(1 * InteropService.Storage.GasPerByte); + debugger.StepInto(); // syscall Storage.Put + + debugger.StepInto(); //push key + debugger.StepInto(); //push value + debugger.StepInto(); + setupPrice = ae.GasConsumed; + var reusedDataPrice = InteropService.GetPrice(InteropService.Storage.Put, ae.CurrentContext.EvaluationStack, ae.Snapshot); + reusedDataPrice.Should().Be(1 * InteropService.Storage.GasPerByte); // = PUT basic fee + } + } + + private byte[] CreateMultiplePutScript(byte[] key, byte[] value, int times = 2) + { + var scriptBuilder = new ScriptBuilder(); + + for (int i = 0; i < times; i++) + { + scriptBuilder.EmitPush(value); + scriptBuilder.EmitPush(key); + scriptBuilder.EmitSysCall(InteropService.Storage.GetContext); + scriptBuilder.EmitSysCall(InteropService.Storage.Put); + } + + return scriptBuilder.ToArray(); + } + + private byte[] CreatePutScript(byte[] key, byte[] value) + { + var scriptBuilder = new ScriptBuilder(); + scriptBuilder.EmitPush(value); + scriptBuilder.EmitPush(key); + scriptBuilder.EmitSysCall(InteropService.Storage.GetContext); + scriptBuilder.EmitSysCall(InteropService.Storage.Put); + return scriptBuilder.ToArray(); + } } } diff --git a/tests/neo.UnitTests/TestUtils.cs b/tests/neo.UnitTests/TestUtils.cs index a68eba49a0..dfbd973a26 100644 --- a/tests/neo.UnitTests/TestUtils.cs +++ b/tests/neo.UnitTests/TestUtils.cs @@ -4,6 +4,7 @@ using Neo.Ledger; using Neo.Network.P2P.Payloads; using Neo.SmartContract.Manifest; +using Neo.SmartContract; using Neo.VM; using Neo.Wallets.NEP6; using System; @@ -64,6 +65,33 @@ internal static ContractState GetContract() }; } + internal static ContractState GetContract(byte[] script) + { + return new ContractState + { + Id = 1, + Script = script, + Manifest = ContractManifest.CreateDefault(script.ToScriptHash()) + }; + } + + internal static StorageItem GetStorageItem(byte[] value) + { + return new StorageItem + { + Value = value + }; + } + + internal static StorageKey GetStorageKey(int id, byte[] keyValue) + { + return new StorageKey + { + Id = id, + Key = keyValue + }; + } + public static void SetupHeaderWithValues(Header header, UInt256 val256, out UInt256 merkRootVal, out UInt160 val160, out ulong timestampVal, out uint indexVal, out Witness scriptVal) { setupBlockBaseWithValues(header, val256, out merkRootVal, out val160, out timestampVal, out indexVal, out scriptVal);