コード例 #1
0
        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);
        }
コード例 #2
0
        public void Handles_well_top_level()
        {
            EstimateGasTracer tracer = new EstimateGasTracer();

            tracer.ReportAction(1000, 0, Address.Zero, Address.Zero, Array.Empty <byte>(), ExecutionType.Transaction, false);
            tracer.ReportActionEnd(600, Array.Empty <byte>());
            tracer.CalculateEstimate(Build.A.Transaction.WithGasLimit(1000).TestObject).Should().Be(0);
        }
コード例 #3
0
        public void Does_not_take_into_account_precompiles()
        {
            EstimateGasTracer tracer = new EstimateGasTracer();

            tracer.ReportAction(1000, 0, Address.Zero, Address.Zero, Array.Empty <byte>(), ExecutionType.Transaction, false);
            tracer.ReportAction(1000, 0, Address.Zero, Address.Zero, Array.Empty <byte>(), ExecutionType.Call, true);
            tracer.ReportActionEnd(400, Array.Empty <byte>()); // this would not happen but we want to ensure that precompiles are ignored
            tracer.ReportActionEnd(600, Array.Empty <byte>());
            tracer.CalculateEstimate(Build.A.Transaction.WithGasLimit(1000).TestObject).Should().Be(0);
        }
コード例 #4
0
        public void Does_not_throw_if_cancellation_token_is_default()
        {
            CancellationToken cancellationToken = default;
            EstimateGasTracer tracer            = new EstimateGasTracer(cancellationToken);
            Transaction       transactionMock   = Substitute.For <Transaction>();

            Thread.Sleep(TimeSpan.FromSeconds(2));

            Assert.DoesNotThrow(() => tracer.CalculateEstimate(transactionMock));
        }
コード例 #5
0
        public CallOutput EstimateGas(BlockHeader header, Transaction tx)
        {
            EstimateGasTracer estimateGasTracer = new EstimateGasTracer();

            CallAndRestore(header, tx, estimateGasTracer);
            long estimate = estimateGasTracer.CalculateEstimate(tx);

            return(new CallOutput {
                Error = estimateGasTracer.Error, GasSpent = estimate
            });
        }
コード例 #6
0
        public CallOutput EstimateGas(BlockHeader header, Transaction tx)
        {
            EstimateGasTracer estimateGasTracer = new EstimateGasTracer(_cancellationToken);

            CallAndRestore(header, tx, UInt256.Max(header.Timestamp + 1, _timestamper.EpochSeconds), estimateGasTracer);
            long estimate = estimateGasTracer.CalculateEstimate(tx);

            return(new CallOutput {
                Error = estimateGasTracer.Error, GasSpent = estimate
            });
        }
コード例 #7
0
        public void Throw_operation_canceled_after_given_timeout()
        {
            TimeSpan          timeout           = TimeSpan.FromMilliseconds(10);
            CancellationToken cancellationToken = new CancellationTokenSource(timeout).Token;
            Transaction       transactionMock   = Substitute.For <Transaction>();
            EstimateGasTracer tracer            = new EstimateGasTracer(cancellationToken);

            Thread.Sleep(timeout.Add(TimeSpan.FromMilliseconds(100)));

            Assert.Throws <OperationCanceledException>(() => tracer.CalculateEstimate(transactionMock));
        }
コード例 #8
0
        public void Easy_one_level_case()
        {
            EstimateGasTracer tracer = new EstimateGasTracer();

            tracer.ReportAction(128, 0, Address.Zero, Address.Zero, Array.Empty <byte>(), ExecutionType.Transaction, false);
            tracer.ReportAction(100, 0, Address.Zero, Address.Zero, Array.Empty <byte>(), _executionType, false);

            tracer.ReportActionEnd(63, Array.Empty <byte>()); // second level
            tracer.ReportActionEnd(65, Array.Empty <byte>());

            tracer.CalculateEstimate(Build.A.Transaction.WithGasLimit(128).TestObject).Should().Be(1);
        }
コード例 #9
0
        public void Can_estimate_simple()
        {
            long        gasLimit = 100000;
            Transaction tx       = Build.A.Transaction.SignedAndResolved(_ethereumEcdsa, TestItem.PrivateKeyA, _isEip155Enabled).WithGasLimit(gasLimit).TestObject;
            Block       block    = Build.A.Block.WithNumber(1).WithTransactions(tx).WithGasLimit(gasLimit).TestObject;

            EstimateGasTracer tracer = new EstimateGasTracer();

            _transactionProcessor.CallAndRestore(tx, block.Header, tracer);

            tracer.GasSpent.Should().Be(21000);
            tracer.CalculateEstimate(tx).Should().Be(21000);
        }
コード例 #10
0
        public CallOutput EstimateGas(BlockHeader header, Transaction tx, CancellationToken cancellationToken)
        {
            EstimateGasTracer estimateGasTracer = new EstimateGasTracer();

            CallAndRestore(
                header,
                header.Number + 1,
                UInt256.Max(header.Timestamp + 1, _timestamper.UnixTime.Seconds),
                tx,
                estimateGasTracer.WithCancellation(cancellationToken));

            long estimate = estimateGasTracer.CalculateEstimate(tx);

            return(new CallOutput {
                Error = estimateGasTracer.Error, GasSpent = estimate
            });
        }
コード例 #11
0
        public void Handles_well_serial_calls()
        {
            EstimateGasTracer tracer = new EstimateGasTracer();

            tracer.ReportAction(1000, 0, Address.Zero, Address.Zero, Array.Empty <byte>(), ExecutionType.Transaction, false);
            tracer.ReportAction(1000, 0, Address.Zero, Address.Zero, Array.Empty <byte>(), _executionType, false);
            tracer.ReportActionEnd(400, Array.Empty <byte>());
            tracer.ReportAction(400, 0, Address.Zero, Address.Zero, Array.Empty <byte>(), _executionType, false);
            if (_executionType.IsAnyCreate())
            {
                tracer.ReportActionEnd(200, Address.Zero, Array.Empty <byte>());
                tracer.ReportActionEnd(300, Array.Empty <byte>());
            }
            else
            {
                tracer.ReportActionEnd(200, Array.Empty <byte>());
                tracer.ReportActionEnd(300, Array.Empty <byte>()); // should not happen
            }

            tracer.CalculateEstimate(Build.A.Transaction.WithGasLimit(1000).TestObject).Should().Be(14L);
        }
コード例 #12
0
        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);
        }
コード例 #13
0
        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);
        }
コード例 #14
0
        public void Handles_well_errors()
        {
            EstimateGasTracer tracer = new EstimateGasTracer();

            tracer.ReportAction(1000, 0, Address.Zero, Address.Zero, Bytes.Empty, ExecutionType.Transaction, false);
            tracer.ReportAction(1000, 0, Address.Zero, Address.Zero, Bytes.Empty, _executionType, false);
            tracer.ReportAction(400, 0, Address.Zero, Address.Zero, Bytes.Empty, _executionType, false);

            if (_executionType.IsAnyCreate())
            {
                tracer.ReportActionError(EvmExceptionType.Other);
                tracer.ReportActionEnd(400, Address.Zero, Bytes.Empty);
                tracer.ReportActionEnd(500, Bytes.Empty); // should not happen
            }
            else
            {
                tracer.ReportActionError(EvmExceptionType.Other);
                tracer.ReportActionEnd(400, Bytes.Empty);
                tracer.ReportActionEnd(500, Bytes.Empty); // should not happen
            }

            tracer.CalculateEstimate(Build.A.Transaction.WithGasLimit(1000).TestObject).Should().Be(24L);
        }
コード例 #15
0
        public void Handles_well_nested_calls_where_least_nested_defines_excess()
        {
            EstimateGasTracer tracer = new EstimateGasTracer();

            tracer.ReportAction(1000, 0, Address.Zero, Address.Zero, Bytes.Empty, ExecutionType.Transaction, false);
            tracer.ReportAction(1000, 0, Address.Zero, Address.Zero, Bytes.Empty, _executionType, false);
            tracer.ReportAction(400, 0, Address.Zero, Address.Zero, Bytes.Empty, _executionType, false);

            if (_executionType.IsAnyCreate())
            {
                tracer.ReportActionEnd(300, Address.Zero, Bytes.Empty); // second level
                tracer.ReportActionEnd(200, Address.Zero, Bytes.Empty);
                tracer.ReportActionEnd(500, Bytes.Empty);               // should not happen
            }
            else
            {
                tracer.ReportActionEnd(300, Bytes.Empty); // second level
                tracer.ReportActionEnd(200, Bytes.Empty);
                tracer.ReportActionEnd(500, Bytes.Empty); // should not happen
            }

            tracer.CalculateEstimate(Build.A.Transaction.WithGasLimit(1000).TestObject).Should().Be(17);
        }
コード例 #16
0
        public void Can_estimate_with_single_call()
        {
            byte[] initByteCode = Prepare.EvmCode
                                  .ForInitOf(Bytes.FromHexString("6000")).Done;

            Address contractAddress = ContractAddress.From(TestItem.PrivateKeyA.Address, 0);

            byte[] byteCode = Prepare.EvmCode
                              .Call(contractAddress, 46179).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();

            _transactionProcessor.CallAndRestore(tx, block.Header, tracer);

            long actualIntrinsic = tx.GasLimit - tracer.IntrinsicGasAt;

            actualIntrinsic.Should().Be(intrinsic);
            tracer.CalculateAdditionalGasRequired(tx).Should().Be(1);
            tracer.GasSpent.Should().Be(54224L);
            long estimate = tracer.CalculateEstimate(tx);

            estimate.Should().Be(54225L);

            ConfirmEnoughEstimate(tx, block, estimate);
        }