public void Call_Contract_Failure() { var parameters = new object[] { }; var contractTxData = new ContractTxData(1, 1, (RuntimeObserver.Gas) 1000, uint160.One, "TestMethod", parameters); StateTransitionResult stateTransitionResult = StateTransitionResult.Fail((RuntimeObserver.Gas) 100, StateTransitionErrorKind.VmError); var fixture = new ExecutorFixture(contractTxData); IState snapshot = fixture.State.Object.Snapshot(); fixture.StateProcessor .Setup(s => s.Apply(snapshot, It.IsAny <ExternalCallMessage>())) .Returns(stateTransitionResult); IStateRepository trackedMock = Mock.Of <IStateRepository>(); fixture.ContractStateRoot.Setup(s => s.StartTracking()).Returns(trackedMock); var sut = new LocalExecutor( fixture.LoggerFactory, fixture.CallDataSerializer.Object, fixture.ContractStateRoot.Object, fixture.StateFactory.Object, fixture.StateProcessor.Object, fixture.ContractPrimitiveSerializer.Object); ILocalExecutionResult result = sut.Execute(fixture.ContractTransactionContext.BlockHeight, fixture.ContractTransactionContext.Sender, fixture.ContractTransactionContext.TxOutValue, contractTxData); fixture.StateFactory.Verify(sf => sf .Create( trackedMock, It.IsAny <IBlock>(), fixture.ContractTransactionContext.TxOutValue, It.IsAny <uint256>()), Times.Once); // We only apply the message to the snapshot. fixture.StateProcessor.Verify(sm => sm.Apply(snapshot, It.Is <ExternalCallMessage>(m => m.Method.Name == contractTxData.MethodName && m.Method.Parameters == contractTxData.MethodParameters && m.Amount == fixture.ContractTransactionContext.TxOutValue && m.From == fixture.ContractTransactionContext.Sender && m.To == contractTxData.ContractAddress)), Times.Once); // Should never transition to the snapshot. fixture.State.Verify(sm => sm.TransitionTo(snapshot), Times.Never); // Should never save on the state fixture.ContractStateRoot.Verify(sr => sr.Commit(), Times.Never); Assert.Equal(stateTransitionResult.Error.VmError, result.ErrorMessage); Assert.True(result.Revert); Assert.Equal <IReadOnlyList <TransferInfo> >(fixture.State.Object.InternalTransfers, result.InternalTransfers); Assert.Equal(stateTransitionResult.GasConsumed, result.GasConsumed); Assert.Null(result.Return); Assert.Equal <IList <Log> >(fixture.State.Object.GetLogs(fixture.ContractPrimitiveSerializer.Object), result.Logs); }
public IActionResult LocalCallSmartContractTransaction([FromBody] BuildCallContractTransactionRequest request) { if (!this.ModelState.IsValid) { return(ModelStateErrors.BuildErrorResponse(this.ModelState)); } // Rewrite the method name to a property name this.RewritePropertyGetterName(request); BuildCallContractTransactionResponse response = this.smartContractTransactionService.BuildCallTx(request); Transaction transaction = this.network.CreateTransaction(response.Hex); var transactionContext = new ContractTransactionContext( (ulong)this.chain.Height, uint160.Zero, 0, // Safe to set this to 0 here, it's only used for the refund which we do not create when executing locally request.Sender.ToUint160(this.network), transaction); ILocalExecutionResult result = this.localExecutor.Execute(transactionContext); return(Json(result)); }
public IActionResult LocalCallSmartContractTransaction([FromBody] LocalCallContractRequest request) { if (!this.ModelState.IsValid) { return(ModelStateErrors.BuildErrorResponse(this.ModelState)); } // Rewrite the method name to a property name this.RewritePropertyGetterName(request); try { ContractTxData txData = this.smartContractTransactionService.BuildLocalCallTxData(request); ILocalExecutionResult result = this.localExecutor.Execute( (ulong)this.chainIndexer.Height, request.Sender?.ToUint160(this.network) ?? new uint160(), string.IsNullOrWhiteSpace(request.Amount) ? (Money)request.Amount : 0, txData); return(this.Json(result, new JsonSerializerSettings { ContractResolver = new ContractParametersContractResolver(this.network) })); } catch (MethodParameterStringSerializerException e) { return(this.Json(ErrorHelpers.BuildErrorResponse(HttpStatusCode.InternalServerError, e.Message, "Error deserializing method parameters"))); } }
public void Create_Contract_Failure() { var contractTxData = new ContractTxData(1, 1, (Gas)1000, new byte[] { 0xAA, 0xBB, 0xCC }); StateTransitionResult stateTransitionResult = StateTransitionResult.Fail((Gas)100, StateTransitionErrorKind.VmError); var fixture = new ExecutorFixture(contractTxData); IState snapshot = fixture.State.Object.Snapshot(); fixture.StateProcessor .Setup(s => s.Apply(snapshot, It.IsAny <ExternalCreateMessage>())) .Returns(stateTransitionResult); IStateRepository trackedMock = Mock.Of <IStateRepository>(); fixture.ContractStateRoot.Setup(s => s.StartTracking()).Returns(trackedMock); var sut = new LocalExecutor( fixture.LoggerFactory, fixture.CallDataSerializer.Object, fixture.ContractStateRoot.Object, fixture.StateFactory.Object, fixture.StateProcessor.Object, fixture.ContractPrimitiveSerializer.Object); ILocalExecutionResult result = sut.Execute(fixture.ContractTransactionContext); fixture.CallDataSerializer.Verify(s => s.Deserialize(fixture.Data), Times.Once); fixture.StateFactory.Verify(sf => sf .Create( trackedMock, It.IsAny <IBlock>(), fixture.ContractTransactionContext.TxOutValue, fixture.ContractTransactionContext.TransactionHash), Times.Once); // We only apply the message to the snapshot. fixture.StateProcessor.Verify(sm => sm.Apply(fixture.State.Object.Snapshot(), It.Is <ExternalCreateMessage>(m => m.Code == contractTxData.ContractExecutionCode && m.Parameters == contractTxData.MethodParameters)), Times.Once); // Should never transition to the snapshot. fixture.State.Verify(sm => sm.TransitionTo(fixture.State.Object.Snapshot()), Times.Never); // Should never save on the state fixture.ContractStateRoot.Verify(sr => sr.Commit(), Times.Never); Assert.Equal(stateTransitionResult.Error.VmError, result.ErrorMessage); Assert.True(result.Revert); Assert.Equal(fixture.State.Object.InternalTransfers, result.InternalTransfers); Assert.Equal(stateTransitionResult.GasConsumed, result.GasConsumed); Assert.Null(result.Return); Assert.Equal(fixture.State.Object.GetLogs(fixture.ContractPrimitiveSerializer.Object), result.Logs); }
public void MockChain_NonFungibleToken() { using (PoWMockChain chain = new PoWMockChain(2)) { MockChainNode node1 = chain.Nodes[0]; MockChainNode node2 = chain.Nodes[1]; node1.MineBlocks(1); ContractCompilationResult compilationResult = ContractCompiler.CompileFile("SmartContracts/NonFungibleToken.cs"); Assert.True(compilationResult.Success); // Create contract and ensure code exists BuildCreateContractTransactionResponse response = node1.SendCreateContractTransaction(compilationResult.Compilation, 0); node2.WaitMempoolCount(1); node2.MineBlocks(1); Assert.NotNull(node2.GetCode(response.NewContractAddress)); Assert.NotNull(node1.GetCode(response.NewContractAddress)); string[] parameters = new string[] { this.methodParameterStringSerializer.Serialize(1uL) }; ILocalExecutionResult result = node1.CallContractMethodLocally("OwnerOf", response.NewContractAddress, 0, parameters); uint160 senderAddressUint160 = node1.MinerAddress.Address.ToUint160(node1.CoreNode.FullNode.Network); uint160 returnedAddressUint160 = ((Address)result.Return).ToUint160(); Assert.Equal(senderAddressUint160, returnedAddressUint160); // Send tokenId 1 to a new owner parameters = new string[] { this.methodParameterStringSerializer.Serialize(node1.MinerAddress.Address.ToAddress(node1.CoreNode.FullNode.Network)), this.methodParameterStringSerializer.Serialize(node2.MinerAddress.Address.ToAddress(node1.CoreNode.FullNode.Network)), this.methodParameterStringSerializer.Serialize(1uL) }; BuildCallContractTransactionResponse callResponse = node1.SendCallContractTransaction("TransferFrom", response.NewContractAddress, 0, parameters); node2.WaitMempoolCount(1); node2.MineBlocks(1); parameters = new string[] { this.methodParameterStringSerializer.Serialize(1uL) }; result = node1.CallContractMethodLocally("OwnerOf", response.NewContractAddress, 0, parameters); uint160 receiverAddressUint160 = node2.MinerAddress.Address.ToUint160(node1.CoreNode.FullNode.Network); returnedAddressUint160 = ((Address)result.Return).ToUint160(); Assert.Equal(receiverAddressUint160, returnedAddressUint160); IList <ReceiptResponse> receipts = node1.GetReceipts(response.NewContractAddress, "Transfer"); Assert.Single(receipts); } }
public LocalExecutionResult LocalCallSmartContractTransaction([FromBody] LocalCallContractRequest request) { // Rewrite the method name to a property name this.RewritePropertyGetterName(request); ContractTxData txData = this.smartContractTransactionService.BuildLocalCallTxData(request); ulong height = request.BlockHeight.HasValue ? request.BlockHeight.Value : (ulong)this.chainIndexer.Height; ILocalExecutionResult result = this.localExecutor.Execute(height, request.Sender?.ToUint160(this.network) ?? new uint160(), string.IsNullOrWhiteSpace(request.Amount) ? (Money)request.Amount : 0, txData); return(result as LocalExecutionResult); }
public void Token_Standards_Test() { const ulong totalSupply = 100_000; // Deploy contract ContractCompilationResult compilationResult = ContractCompiler.CompileFile("SmartContracts/StandardToken.cs"); Assert.True(compilationResult.Success); string[] constructorParams = new string[] { string.Format("{0}#{1}", (int)MethodParameterDataType.UInt, totalSupply) }; BuildCreateContractTransactionResponse preResponse = this.node1.SendCreateContractTransaction(compilationResult.Compilation, 0, constructorParams); this.mockChain.WaitAllMempoolCount(1); this.mockChain.MineBlocks(1); Assert.NotNull(this.node1.GetCode(preResponse.NewContractAddress)); decimal amount = 0; // Send amount to contract, which will send to wallet address (address without code) var base58Address = this.node1.MinerAddress.Address; string[] parameters = new string[] { string.Format("{0}#{1}", (int)MethodParameterDataType.Address, base58Address) }; BuildCallContractTransactionResponse response = this.node1.SendCallContractTransaction( nameof(StandardToken.GetBalance), preResponse.NewContractAddress, amount, parameters); this.mockChain.WaitAllMempoolCount(1); this.mockChain.MineBlocks(1); // Contract doesn't maintain any balance Assert.Equal((ulong)0, this.node1.GetContractBalance(preResponse.NewContractAddress)); ILocalExecutionResult result = this.node1.CallContractMethodLocally("GetBalance", preResponse.NewContractAddress, 0, parameters); Assert.Equal(totalSupply, result.Return); // Receipt is correct ReceiptResponse receipt = this.node1.GetReceipt(response.TransactionId.ToString()); Assert.Equal(response.TransactionId.ToString(), receipt.TransactionHash); Assert.Empty(receipt.Logs); // TODO: Could add logs to this test Assert.True(receipt.Success); Assert.True(receipt.GasUsed > GasPriceList.BaseCost); Assert.Null(receipt.NewContractAddress); Assert.Equal(this.node1.MinerAddress.Address, receipt.From); Assert.Null(receipt.Error); Assert.Equal(preResponse.NewContractAddress, receipt.To); }
public IActionResult LocalCallSmartContractTransaction([FromBody] LocalCallContractRequest request) { if (!this.ModelState.IsValid) { return(ModelStateErrors.BuildErrorResponse(this.ModelState)); } // Rewrite the method name to a property name this.RewritePropertyGetterName(request); try { ContractTxData txData = this.smartContractTransactionService.BuildLocalCallTxData(request); var height = request.BlockHeight.HasValue ? request.BlockHeight.Value : (ulong)this.chainIndexer.Height; ILocalExecutionResult result = this.localExecutor.Execute( height, request.Sender?.ToUint160(this.network) ?? new uint160(), !string.IsNullOrWhiteSpace(request.Amount) ? (Money)request.Amount : 0, txData); var deserializer = new ApiLogDeserializer(this.primitiveSerializer, this.network, result.StateRoot, this.contractAssemblyCache); var response = new LocalExecutionResponse { InternalTransfers = deserializer.MapTransferInfo(result.InternalTransfers.ToArray()), Logs = deserializer.MapLogResponses(result.Logs.ToArray()), GasConsumed = result.GasConsumed, Revert = result.Revert, ErrorMessage = result.ErrorMessage, Return = result.Return // All return values should be primitives, let default serializer handle. }; return(this.Json(response, new JsonSerializerSettings { ContractResolver = new ContractParametersContractResolver(this.network) })); } catch (MethodParameterStringSerializerException e) { return(this.Json(ErrorHelpers.BuildErrorResponse(HttpStatusCode.InternalServerError, e.Message, "Error deserializing method parameters"))); } }
public void TestChain_Auction() { // Compile the contract we want to deploy ContractCompilationResult compilationResult = ContractCompiler.CompileFile("SmartContracts/Auction.cs"); Assert.True(compilationResult.Success); using (TestChain chain = new TestChain().Initialize()) { // Get an address we can use for deploying Base58Address deployerAddress = chain.PreloadedAddresses[0]; // Create and send transaction to mempool with parameters SendCreateContractResult createResult = chain.SendCreateContractTransaction(deployerAddress, compilationResult.Compilation, 0, new object[] { 20uL }); // Mine a block which will contain our sent transaction chain.MineBlocks(1); // Check the receipt to see that contract deployment was successful ReceiptResponse receipt = chain.GetReceipt(createResult.TransactionId); Assert.Equal(deployerAddress, receipt.From); // Check that the code is indeed saved on-chain byte[] savedCode = chain.GetCode(createResult.NewContractAddress); Assert.NotNull(savedCode); // Use another identity to bid Base58Address bidderAddress = chain.PreloadedAddresses[1]; // Send a call to the bid method SendCallContractResult callResult = chain.SendCallContractTransaction(bidderAddress, "Bid", createResult.NewContractAddress, 1); chain.MineBlocks(1); // Call a method locally to check the state is as expected ILocalExecutionResult localCallResult = chain.CallContractMethodLocally(bidderAddress, "HighestBidder", createResult.NewContractAddress, 0); Address storedHighestBidder = (Address)localCallResult.Return; Assert.NotEqual(default(Address), storedHighestBidder); // TODO: A nice way of comparing hex and base58 representations } }
public void Call_Contract_Success() { var parameters = new object[] { }; var contractTxData = new ContractTxData(1, 1, (Gas)1000, uint160.One, "TestMethod", parameters); VmExecutionResult vmExecutionResult = VmExecutionResult.Ok(new object(), null); StateTransitionResult stateTransitionResult = StateTransitionResult.Ok((Gas)100, uint160.One, vmExecutionResult.Success.Result); var fixture = new ExecutorFixture(contractTxData); IState snapshot = fixture.State.Object.Snapshot(); fixture.StateProcessor .Setup(s => s.Apply(snapshot, It.IsAny <ExternalCallMessage>())) .Returns(stateTransitionResult); IStateRepository trackedMock = Mock.Of <IStateRepository>(); fixture.ContractStateRoot.Setup(s => s.StartTracking()).Returns(trackedMock); var sut = new LocalExecutor( fixture.LoggerFactory, fixture.CallDataSerializer.Object, fixture.ContractStateRoot.Object, fixture.StateFactory.Object, fixture.StateProcessor.Object, fixture.ContractPrimitiveSerializer.Object); ILocalExecutionResult result = sut.Execute(fixture.ContractTransactionContext); fixture.CallDataSerializer.Verify(s => s.Deserialize(fixture.ContractTransactionContext.Data), Times.Once); // Local executor used a tracked staterepository fixture.StateFactory.Verify(sf => sf .Create( trackedMock, It.IsAny <IBlock>(), fixture.ContractTransactionContext.TxOutValue, fixture.ContractTransactionContext.TransactionHash), Times.Once); // We only apply the message to the snapshot. fixture.StateProcessor.Verify(sm => sm.Apply(snapshot, It.Is <ExternalCallMessage>(m => m.Method.Name == contractTxData.MethodName && m.Method.Parameters == contractTxData.MethodParameters && m.Amount == fixture.ContractTransactionContext.TxOutValue && m.From == fixture.ContractTransactionContext.Sender && m.To == contractTxData.ContractAddress)), Times.Once); // Should never transition to the snapshot. fixture.State.Verify(sm => sm.TransitionTo(snapshot), Times.Never); // Should never save on the state fixture.ContractStateRoot.Verify(sr => sr.Commit(), Times.Never); Assert.Null(result.ErrorMessage); Assert.False(result.Revert); Assert.Equal(fixture.State.Object.InternalTransfers, result.InternalTransfers); Assert.Equal(stateTransitionResult.GasConsumed, result.GasConsumed); Assert.Equal(stateTransitionResult.Success.ExecutionResult, result.Return); Assert.Equal(fixture.State.Object.GetLogs(fixture.ContractPrimitiveSerializer.Object), result.Logs); }