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();
        }
Ejemplo n.º 3
0
        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());
        }
Ejemplo n.º 4
0
        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);
        }
Ejemplo n.º 6
0
        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));
        }
Ejemplo n.º 7
0
        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());
        }
Ejemplo n.º 8
0
        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'));
        }
Ejemplo n.º 9
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());
        }
Ejemplo n.º 10
0
        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);
        }
Ejemplo n.º 11
0
        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");
        }
Ejemplo n.º 12
0
        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));
        }
Ejemplo n.º 13
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");
        }
Ejemplo n.º 14
0
        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();
                }
            }
        }