public void Can_estimate_with_stipend() { byte[] initByteCode = Prepare.EvmCode .CallWithValue(Address.Zero, 0, 1) .Op(Instruction.STOP) .Done; long gasLimit = 100000; Transaction tx = Build.A.Transaction.SignedAndResolved(_ethereumEcdsa, TestItem.PrivateKeyA, _isEip155Enabled).WithInit(initByteCode).WithGasLimit(gasLimit).TestObject; Block block = Build.A.Block.WithNumber(MainnetSpecProvider.MuirGlacierBlockNumber).WithTransactions(tx).WithGasLimit(2 * gasLimit).TestObject; IntrinsicGasCalculator gasCalculator = new IntrinsicGasCalculator(); long intrinsic = gasCalculator.Calculate(tx, MuirGlacier.Instance); GethLikeTxTracer gethTracer = new GethLikeTxTracer(GethTraceOptions.Default); _transactionProcessor.CallAndRestore(tx, block.Header, gethTracer); TestContext.WriteLine(new EthereumJsonSerializer().Serialize(gethTracer.BuildResult(), true)); EstimateGasTracer tracer = new EstimateGasTracer(); _transactionProcessor.CallAndRestore(tx, block.Header, tracer); long actualIntrinsic = tx.GasLimit - tracer.IntrinsicGasAt; actualIntrinsic.Should().Be(intrinsic); tracer.CalculateAdditionalGasRequired(tx).Should().Be(2300); tracer.GasSpent.Should().Be(85669L); long estimate = tracer.CalculateEstimate(tx); estimate.Should().Be(87969L); ConfirmEnoughEstimate(tx, block, estimate); }
private void ConfirmEnoughEstimate(Transaction tx, Block block, long estimate) { CallOutputTracer outputTracer = new CallOutputTracer(); tx.GasLimit = estimate; TestContext.WriteLine(tx.GasLimit); GethLikeTxTracer gethTracer = new GethLikeTxTracer(GethTraceOptions.Default); _transactionProcessor.CallAndRestore(tx, block.Header, gethTracer); string traceEnoughGas = new EthereumJsonSerializer().Serialize(gethTracer.BuildResult(), true); _transactionProcessor.CallAndRestore(tx, block.Header, outputTracer); traceEnoughGas.Should().NotContain("OutOfGas"); outputTracer = new CallOutputTracer(); tx.GasLimit = Math.Min(estimate - 1, estimate * 63 / 64); TestContext.WriteLine(tx.GasLimit); gethTracer = new GethLikeTxTracer(GethTraceOptions.Default); _transactionProcessor.CallAndRestore(tx, block.Header, gethTracer); string traceOutOfGas = new EthereumJsonSerializer().Serialize(gethTracer.BuildResult(), true); TestContext.WriteLine(traceOutOfGas); _transactionProcessor.CallAndRestore(tx, block.Header, outputTracer); bool failed = traceEnoughGas.Contains("failed") || traceEnoughGas.Contains("OutOfGas"); failed.Should().BeTrue(); }
protected GethLikeTxTrace ExecuteAndTrace(params byte[] code) { GethLikeTxTracer tracer = new GethLikeTxTracer(); (var block, var transaction) = PrepareTx(BlockNumber, 100000, code); _processor.Execute(transaction, block.Header, tracer); return(tracer.BuildResult()); }
protected GethLikeTxTrace ExecuteAndTrace(long blockNumber, long gasLimit, params byte[] code) { GethLikeTxTracer tracer = new GethLikeTxTracer(GethTraceOptions.Default); (var block, var transaction) = PrepareTx(blockNumber, gasLimit, code); _processor.Execute(transaction, block.Header, tracer); return(tracer.BuildResult()); }
/* * also need to test: * BALANCE * EXTCODECOPY * CALLDATACOPY * GASPRICE * CREATE */ private static GethLikeTxTracer RunVirtualMachine(byte[] code) { var txTracer = new GethLikeTxTracer(GethTraceOptions.Default); IDb stateDbDevice = new MemDb(); IDb codeDbDevice = new MemDb(); ISnapshotableDb stateDb = new StateDb(stateDbDevice); ISnapshotableDb codeDb = new StateDb(codeDbDevice); IStateProvider stateProvider = new StateProvider(stateDb, codeDb, LimboLogs.Instance); IStorageProvider storageProvider = new StorageProvider(stateDb, stateProvider, LimboLogs.Instance); IStateUpdateHashProvider stateUpdateHashProvider = new StateUpdateHashProvider(); ISpecProvider specProvider = new CatalystSpecProvider(); // these values will be set by the tx processor within the state update logic var env = new ExecutionEnvironment(); env.Originator = Address.Zero; // tx sender env.Sender = Address.Zero; // sender of this call for a given call depth env.ExecutingAccount = Address.Zero; // account in which context the code is executed, it may be different from the code source when invoking a lib env.Value = 1 .Kat(); // sometimes the value is just a description of an upper level call to be used by a an invoke library method env.TransferValue = 1.Kat(); // this is the actual value transferred from sender to recipient env.GasPrice = 0; // conversion from gas units to FULs env.InputData = new byte[0]; // only needed for contracts requiring input (ensure that this is not limited to 60bytes) env.CallDepth = 0; // zero when starting tx var stateUpdate = new StateUpdate(); // Catalyst single state update context (all phases together) stateUpdate.Difficulty = 1; // some metric describing the state update that is relevant for consensus stateUpdate.Number = 1; // state update sequence number stateUpdate.Timestamp = 1; // state update T0 stateUpdate.GasLimit = 1_000_000; // max gas units to be available for this tx inside the kvm stateUpdate.GasBeneficiary = Address.Zero; // will get all the gas fees stateUpdate.GasUsed = 0L; // zero if this is the first transaction in the update (accumulator over txs) env.CurrentBlock = stateUpdate; // this would be loaded by the tx processor from the recipient's code storage var codeInfo = new CodeInfo(code); env.CodeInfo = codeInfo; env.CodeSource = Address.Zero; // this would be set by the tx processor that understands the type of transaction var vmState = new VmState(1_000_000L, env, ExecutionType.Transaction, false, true, false); var virtualMachine = new KatVirtualMachine(stateProvider, storageProvider, stateUpdateHashProvider, specProvider, LimboLogs.Instance); virtualMachine.Run(vmState, txTracer); return(txTracer); }
public void Can_Run_Smoke_test() { var code = Bytes.FromHexString("0x600060000100"); GethLikeTxTracer txTracer = RunVirtualMachine(code); EthereumJsonSerializer serializer = new EthereumJsonSerializer(); var trace = txTracer.BuildResult(); _testOutputHelper.WriteLine(serializer.Serialize(trace, true)); }
public void Can_Invoke_Address() { var code = Bytes.FromHexString("0x3000"); GethLikeTxTracer txTracer = RunVirtualMachine(code); EthereumJsonSerializer serializer = new EthereumJsonSerializer(); var trace = txTracer.BuildResult(); _testOutputHelper.WriteLine(serializer.Serialize(trace, true)); trace.Failed.Should().Be(false); trace.Entries.Last().Stack.Count.Should().Be(1); trace.Entries.Last().Stack.Last().Should().Be(VirtualMachine.BytesZero32.ToHexString()); }
public void Can_Invoke_Gas_Limit() { var code = Bytes.FromHexString("0x4500"); GethLikeTxTracer txTracer = RunVirtualMachine(code); EthereumJsonSerializer serializer = new EthereumJsonSerializer(); var trace = txTracer.BuildResult(); _testOutputHelper.WriteLine(serializer.Serialize(trace, true)); trace.Failed.Should().Be(false); trace.Entries.Last().Stack.Count.Should().Be(1); trace.Entries.Last().Stack.Last().Should().Be("f4240".PadLeft(64, '0')); }
public void Can_Invoke_Range_Proof_Precompile() { var code = Bytes.FromHexString("0x60008080806201000062050000F400"); GethLikeTxTracer txTracer = RunVirtualMachine(code); EthereumJsonSerializer serializer = new EthereumJsonSerializer(); GethLikeTxTrace trace = txTracer.BuildResult(); TestContext.WriteLine(serializer.Serialize(trace, true)); trace.Failed.Should().Be(false); trace.Entries.Last().Stack.Count.Should().Be(1); trace.Entries.Last().Stack.Last().Should().Be(VirtualMachine.BytesOne32.ToHexString()); }
public void Tracers_cancellation_tokens_does_not_affect_each_other() { GethTraceOptions optionsMock = Substitute.For <GethTraceOptions>(); CancellationToken cancellationToken = new CancellationTokenSource(TimeSpan.FromMilliseconds(1)).Token; var tracer = new GethLikeTxTracer(optionsMock, cancellationToken); CancellationToken cancellationToken2 = new CancellationTokenSource().Token; var tracer2 = new GethLikeTxTracer(optionsMock, cancellationToken2);; Thread.Sleep(5); Assert.AreNotEqual(cancellationToken, cancellationToken2); }
public void Blake_precompile() { Address blakeAddress = Address.FromNumber(1 + KatVirtualMachine.CatalystPrecompilesAddressingSpace); string addressCode = blakeAddress.Bytes.ToHexString(false); var code = Bytes.FromHexString("0x602060006080600073" + addressCode + "45fa00"); GethLikeTxTracer txTracer = RunVirtualMachine(code); EthereumJsonSerializer serializer = new EthereumJsonSerializer(); GethLikeTxTrace trace = txTracer.BuildResult(); TestContext.WriteLine(serializer.Serialize(trace, true)); trace.Entries.Last().Stack.First().Should().Be("0000000000000000000000000000000000000000000000000000000000000001"); trace.Entries.Last().Memory.First().Should().Be("378d0caaaa3855f1b38693c1d6ef004fd118691c95c959d4efa950d6d6fcf7c1"); }
public void Throw_operation_canceled_after_given_timeout() { var timeout = TimeSpan.FromSeconds(1); CancellationToken cancellationToken = new CancellationTokenSource(timeout).Token; GethTraceOptions optionsMock = Substitute.For <GethTraceOptions>(); var tracer = new GethLikeTxTracer(optionsMock, cancellationToken); Thread.Sleep(TimeSpan.FromSeconds(2)); Assert.Throws <OperationCanceledException>(() => tracer.ReportOperationRemainingGas(0)); Assert.Throws <OperationCanceledException>(() => tracer.SetOperationMemorySize(0)); Assert.Throws <OperationCanceledException>(() => tracer.StartOperation(0, 0, Instruction.ADD, 0)); }
public void Ed25519_precompile_can_verify_correct_sig() { HashProvider hashProvider = new HashProvider(HashingAlgorithm.GetAlgorithmMetadata("blake2b-256")); FfiWrapper cryptoContext = new FfiWrapper(); IPrivateKey signingPrivateKey = cryptoContext.GeneratePrivateKey(); var signingPublicKeyBytes = signingPrivateKey.GetPublicKey().Bytes; var byteCode = PrepareEd25519PrecompileCall(hashProvider, cryptoContext, signingPrivateKey, signingPrivateKey); GethLikeTxTracer txTracer = RunVirtualMachine(byteCode); EthereumJsonSerializer serializer = new EthereumJsonSerializer(); GethLikeTxTrace trace = txTracer.BuildResult(); TestContext.WriteLine(serializer.Serialize(trace, true)); trace.Entries.Last().Stack.First().Should().Be("0000000000000000000000000000000000000000000000000000000000000001"); trace.Entries.Last().Memory.First().Should().StartWith("01"); }
public void Ed25519_precompile_can_report_too_long_input() { var byteCode = Bytes.FromHexString( // PUSH1 32 PUSH1 0 PUSH1 192 PUSH1 0 PUSH20 address GAS STATICCALL // make a call to precompile and pass invalid [0,192) bytes of memory as an input // and store result at [0,1) of memory array // allow precompile to use all the gas required "6001600060c0600073" + GetEd25519PrecompileAddressAsHex() + "45fa00"); GethLikeTxTracer txTracer = RunVirtualMachine(byteCode); EthereumJsonSerializer serializer = new EthereumJsonSerializer(); GethLikeTxTrace trace = txTracer.BuildResult(); TestContext.WriteLine(serializer.Serialize(trace, true)); trace.Entries.Last().Stack.First().Should().Be("0000000000000000000000000000000000000000000000000000000000000000"); }
public void Can_estimate_with_refund() { byte[] initByteCode = Prepare.EvmCode .PushData(1) .PushData(1) .Op(Instruction.SSTORE) .PushData(0) .PushData(1) .Op(Instruction.SSTORE) .Op(Instruction.STOP) .Done; long gasLimit = 100000; Transaction tx = Build.A.Transaction.SignedAndResolved(_ethereumEcdsa, TestItem.PrivateKeyA, 1).WithInit(initByteCode).WithGasLimit(gasLimit).TestObject; Block block = Build.A.Block.WithNumber(MainnetSpecProvider.MuirGlacierBlockNumber).WithTransactions(tx).WithGasLimit(2 * gasLimit).TestObject; IntrinsicGasCalculator gasCalculator = new IntrinsicGasCalculator(); long intrinsic = gasCalculator.Calculate(tx, MuirGlacier.Instance); GethLikeTxTracer gethTracer = new GethLikeTxTracer(GethTraceOptions.Default); _transactionProcessor.CallAndRestore(tx, block.Header, gethTracer); TestContext.WriteLine(new EthereumJsonSerializer().Serialize(gethTracer.BuildResult(), true)); EstimateGasTracer tracer = new EstimateGasTracer(); _transactionProcessor.CallAndRestore(tx, block.Header, tracer); long actualIntrinsic = tx.GasLimit - tracer.IntrinsicGasAt; actualIntrinsic.Should().Be(intrinsic); tracer.CalculateAdditionalGasRequired(tx).Should().Be(RefundOf.SSetReversedEip2200 + GasCostOf.CallStipend - GasCostOf.SStoreNetMeteredEip2200 + 1); tracer.GasSpent.Should().Be(54764L); long estimate = tracer.CalculateEstimate(tx); estimate.Should().Be(75465L); ConfirmEnoughEstimate(tx, block, estimate); }
public void Can_estimate_with_destroy_refund_and_below_intrinsic() { byte[] initByteCode = Prepare.EvmCode.ForInitOf(Prepare.EvmCode.PushData(Address.Zero).Op(Instruction.SELFDESTRUCT).Done).Done; Address contractAddress = ContractAddress.From(TestItem.PrivateKeyA.Address, 0); byte[] byteCode = Prepare.EvmCode .Call(contractAddress, 46179) .Op(Instruction.STOP).Done; long gasLimit = 100000; Transaction initTx = Build.A.Transaction.SignedAndResolved(_ethereumEcdsa, TestItem.PrivateKeyA, _isEip155Enabled).WithInit(initByteCode).WithGasLimit(gasLimit).TestObject; Transaction tx = Build.A.Transaction.SignedAndResolved(_ethereumEcdsa, TestItem.PrivateKeyA, _isEip155Enabled).WithInit(byteCode).WithGasLimit(gasLimit).WithNonce(1).TestObject; Block block = Build.A.Block.WithNumber(MainnetSpecProvider.MuirGlacierBlockNumber).WithTransactions(tx).WithGasLimit(2 * gasLimit).TestObject; IntrinsicGasCalculator gasCalculator = new IntrinsicGasCalculator(); long intrinsic = gasCalculator.Calculate(tx, MuirGlacier.Instance); _transactionProcessor.Execute(initTx, block.Header, NullTxTracer.Instance); EstimateGasTracer tracer = new EstimateGasTracer(); GethLikeTxTracer gethTracer = new GethLikeTxTracer(GethTraceOptions.Default); _transactionProcessor.CallAndRestore(tx, block.Header, tracer); _transactionProcessor.CallAndRestore(tx, block.Header, gethTracer); TestContext.WriteLine(new EthereumJsonSerializer().Serialize(gethTracer.BuildResult(), true)); long actualIntrinsic = tx.GasLimit - tracer.IntrinsicGasAt; actualIntrinsic.Should().Be(intrinsic); tracer.CalculateAdditionalGasRequired(tx).Should().Be(24080); tracer.GasSpent.Should().Be(35228L); long estimate = tracer.CalculateEstimate(tx); estimate.Should().Be(59308); ConfirmEnoughEstimate(tx, block, estimate); }
public void Does_not_throw_operation_canceled_if_cancellation_token_is_default() { GethTraceOptions optionsMock = Substitute.For <GethTraceOptions>(); CancellationToken cancellationToken = default(CancellationToken); var tracer = new GethLikeTxTracer(optionsMock, cancellationToken); Thread.Sleep(TimeSpan.FromSeconds(2)); try { tracer.StartOperation(0, 0, Instruction.ADD, 0); } catch (Exception ex) { if (ex is OperationCanceledException) { Assert.Fail("Tracer throw OperationCanceledException even when cancellation token is set to default."); } else { Assert.Pass(); } } }