public void SmartContract_CanSerialize_OP_CREATECONTRACT_WithoutMethodParameters() { byte[] contractExecutionCode = Encoding.UTF8.GetBytes( @" using System; using Stratis.SmartContracts; [References] public class Test : SmartContract { public void TestMethod() { [CodeToExecute] } }" ); var carrier = SmartContractCarrier.CreateContract(1, contractExecutionCode, 1, (Gas)5000); var serializedCarrier = carrier.Serialize(); var tx = new Transaction(); tx.AddInput(new TxIn(new OutPoint(0, 0), new Script(OpcodeType.OP_1))); tx.AddOutput(new TxOut(new Money(5000000000L - 10000), new Script(serializedCarrier))); SmartContractCarrier deserialized = SmartContractCarrier.Deserialize(tx); Assert.Equal(1, deserialized.CallData.VmVersion); Assert.Equal((byte)ScOpcodeType.OP_CREATECONTRACT, deserialized.CallData.OpCodeType); Assert.Equal(contractExecutionCode, deserialized.CallData.ContractExecutionCode); Assert.Equal((Gas)1, deserialized.CallData.GasPrice); Assert.Equal((Gas)5000, deserialized.CallData.GasLimit); Assert.True(tx.Outputs[0].ScriptPubKey.IsSmartContractExec()); }
public string GetAddressFromScriptPubKey(Network network, Script script) { if (script.IsSmartContractCreate() || script.IsSmartContractCall()) { var carrier = SmartContractCarrier.Deserialize(script); return(carrier.ContractAddress?.ToAddress(network)); } return(this.baseAddressReader.GetAddressFromScriptPubKey(network, script)); }
public void SmartContract_CanSerialize_OP_CALLCONTRACT_WithoutMethodParameters() { var smartContractCarrier = SmartContractCarrier.CallContract(1, 100, "Execute", 1, (Gas)500000); var tx = new Transaction(); tx.AddInput(new TxIn(new OutPoint(0, 0), new Script(OpcodeType.OP_1))); tx.AddOutput(new TxOut(new Money(5000000000L - 10000), new Script(smartContractCarrier.Serialize()))); SmartContractCarrier deserialized = SmartContractCarrier.Deserialize(tx); Assert.Equal(smartContractCarrier.CallData.VmVersion, deserialized.CallData.VmVersion); Assert.Equal(smartContractCarrier.CallData.OpCodeType, deserialized.CallData.OpCodeType); Assert.Equal(smartContractCarrier.CallData.ContractAddress, deserialized.CallData.ContractAddress); Assert.Equal(smartContractCarrier.CallData.MethodName, deserialized.CallData.MethodName); Assert.Equal(smartContractCarrier.CallData.GasPrice, deserialized.CallData.GasPrice); Assert.Equal(smartContractCarrier.CallData.GasLimit, deserialized.CallData.GasLimit); }
public void TransferProcessor_NoBalance_NoTransfers() { // Scenario where contract was sent 0, doesn't yet have any UTXO assigned, and no transfers were made. var carrierSkeleton = SmartContractCarrier.CallContract(1, new uint160(1), "Test", 1, (Gas)100_000); var transaction = new Transaction(); transaction.AddOutput(0, new Script(carrierSkeleton.Serialize())); var carrier = SmartContractCarrier.Deserialize(transaction); var stateMock = new Mock <IContractStateRepository>(); stateMock.Setup(x => x.GetCode(It.IsAny <uint160>())).Returns <byte[]>(null); var txContextMock = new Mock <ISmartContractTransactionContext>(); var result = new SmartContractExecutionResult(); this.transferProcessor.Process(carrier, stateMock.Object, txContextMock.Object, new List <TransferInfo>(), false); // Ensure no state changes were made and no transaction has been added Assert.Null(result.InternalTransaction); }
private void CheckTransaction(Transaction transaction, Money suppliedBudget) { if (!transaction.IsSmartContractExecTransaction()) { return; } // TODO: What if deserialization throws an error? We should check this. // Also the deserializer should throw custom exceptions. SmartContractCarrier carrier = SmartContractCarrier.Deserialize(transaction); if (carrier.CallData.GasPrice < GasPriceMinimum) { // Supplied gas price is too low. this.ThrowGasPriceLessThanMinimum(); } if (carrier.CallData.GasPrice > GasPriceMaximum) { // Supplied gas price is too high. this.ThrowGasPriceMoreThanMaximum(); } if (carrier.CallData.GasLimit < GasLimitMinimum) { // Supplied gas limit is too low. this.ThrowGasLessThanBaseFee(); } if (carrier.CallData.GasLimit > GasLimitMaximum) { // Supplied gas limit is too high - at a certain point we deem that a contract is taking up too much time. this.ThrowGasGreaterThanHardLimit(); } // Note carrier.GasCostBudget cannot overflow given values are within constraints above. if (suppliedBudget < new Money(carrier.GasCostBudget)) { // Supplied satoshis are less than the budget we said we had for the contract execution this.ThrowGasGreaterThanFee(); } }
public void TransferProcessor_NoBalance_ReceivedFunds() { // Scenario where contract was sent some funds, doesn't yet have any UTXO assigned, and no transfers were made. var carrierSkeleton = SmartContractCarrier.CallContract(1, new uint160(1), "Test", 1, (Gas)100_000); var transaction = new Transaction(); transaction.AddOutput(100, new Script(carrierSkeleton.Serialize())); var carrier = SmartContractCarrier.Deserialize(transaction); var stateMock = new Mock <IContractStateRepository>(); stateMock.Setup(x => x.GetCode(It.IsAny <uint160>())).Returns <byte[]>(null); var txContextMock = new Mock <ISmartContractTransactionContext>(); var result = new SmartContractExecutionResult(); this.transferProcessor.Process(carrier, stateMock.Object, txContextMock.Object, new List <TransferInfo>(), false); // Ensure unspent was saved, but no condensing transaction was generated. Assert.Null(result.InternalTransaction); stateMock.Verify(x => x.SetUnspent(new uint160(1), It.IsAny <ContractUnspentOutput>())); }
public void SmartContract_CanSerialize_OP_CREATECONTRACT_WithMethodParameters() { byte[] contractExecutionCode = Encoding.UTF8.GetBytes( @" using System; using Stratis.SmartContracts; [References] public class Test : SmartContract { public void TestMethod(int orders, bool canOrder) { [CodeToExecute] } }" ); string[] methodParameters = new string[] { string.Format("{0}#{1}", (int)SmartContractCarrierDataType.Short, 12), string.Format("{0}#{1}", (int)SmartContractCarrierDataType.Bool, true), string.Format("{0}#{1}", (int)SmartContractCarrierDataType.String, "te|s|t"), string.Format("{0}#{1}", (int)SmartContractCarrierDataType.String, "te#st"), string.Format("{0}#{1}", (int)SmartContractCarrierDataType.String, "#4#te#st#"), string.Format("{0}#{1}", (int)SmartContractCarrierDataType.Char, '#'), }; var carrier = SmartContractCarrier.CreateContract(1, contractExecutionCode, 1, (Gas)500000, methodParameters); var tx = new Transaction(); tx.AddInput(new TxIn(new OutPoint(0, 0), new Script(OpcodeType.OP_1))); tx.AddOutput(new TxOut(new Money(5000000000L - 10000), new Script(carrier.Serialize()))); SmartContractCarrier deserialized = SmartContractCarrier.Deserialize(tx); Assert.Equal(carrier.CallData.VmVersion, deserialized.CallData.VmVersion); Assert.Equal(carrier.CallData.OpCodeType, deserialized.CallData.OpCodeType); Assert.Equal(carrier.CallData.ContractExecutionCode, deserialized.CallData.ContractExecutionCode); Assert.Equal(6, deserialized.MethodParameters.Length); Assert.NotNull(carrier.MethodParameters[0]); Assert.Equal(12, deserialized.MethodParameters[0]); Assert.NotNull(carrier.MethodParameters[1]); Assert.True((bool)deserialized.MethodParameters[1]); Assert.NotNull(carrier.MethodParameters[2]); Assert.Equal("te|s|t", deserialized.MethodParameters[2]); Assert.NotNull(carrier.MethodParameters[3]); Assert.Equal("te#st", deserialized.MethodParameters[3]); Assert.NotNull(carrier.MethodParameters[4]); Assert.Equal("#4#te#st#", deserialized.MethodParameters[4]); Assert.NotNull(carrier.MethodParameters[5]); Assert.Equal("#", deserialized.MethodParameters[5]); Assert.Equal(carrier.CallData.GasPrice, deserialized.CallData.GasPrice); Assert.Equal(carrier.CallData.GasLimit, deserialized.CallData.GasLimit); }
public void SmartContract_CanSerialize_OP_CALLCONTRACT_WithMethodParameters() { string[] methodParameters = new string[] { string.Format("{0}#{1}", (int)SmartContractCarrierDataType.Bool, true), string.Format("{0}#{1}", (int)SmartContractCarrierDataType.Byte, (byte)1), string.Format("{0}#{1}", (int)SmartContractCarrierDataType.ByteArray, BitConverter.ToString(Encoding.UTF8.GetBytes("test"))), string.Format("{0}#{1}", (int)SmartContractCarrierDataType.Char, 's'), string.Format("{0}#{1}", (int)SmartContractCarrierDataType.SByte, -45), string.Format("{0}#{1}", (int)SmartContractCarrierDataType.Short, 7), string.Format("{0}#{1}", (int)SmartContractCarrierDataType.String, "test"), string.Format("{0}#{1}", (int)SmartContractCarrierDataType.UInt, 36), string.Format("{0}#{1}", (int)SmartContractCarrierDataType.UInt160, new uint160(new byte[20] { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 })), string.Format("{0}#{1}", (int)SmartContractCarrierDataType.ULong, 29), string.Format("{0}#{1}", (int)SmartContractCarrierDataType.Address, new Address("0x95D34980095380851902ccd9A1Fb4C813C2cb639")), string.Format("{0}#{1}", (int)SmartContractCarrierDataType.Address, new Address("mxKorCkWmtrPoekfWiMzERJPhaT13nnkMy")) }; var carrier = SmartContractCarrier.CallContract(1, 100, "Execute", 1, (Gas)500000, methodParameters); var tx = new Transaction(); tx.AddInput(new TxIn(new OutPoint(0, 0), new Script(OpcodeType.OP_1))); tx.AddOutput(new TxOut(new Money(5000000000L - 10000), new Script(carrier.Serialize()))); SmartContractCarrier deserialized = SmartContractCarrier.Deserialize(tx); Assert.NotNull(deserialized.MethodParameters[0]); Assert.Equal(carrier.MethodParameters[0], deserialized.MethodParameters[0]); Assert.NotNull(deserialized.MethodParameters[1]); Assert.Equal(carrier.MethodParameters[1], deserialized.MethodParameters[1]); Assert.NotNull(deserialized.MethodParameters[2]); Assert.Equal(carrier.MethodParameters[2], deserialized.MethodParameters[2]); Assert.NotNull(deserialized.MethodParameters[3]); Assert.Equal(carrier.MethodParameters[3], deserialized.MethodParameters[3]); Assert.NotNull(deserialized.MethodParameters[4]); Assert.Equal(carrier.MethodParameters[4], deserialized.MethodParameters[4]); Assert.NotNull(deserialized.MethodParameters[5]); Assert.Equal(carrier.MethodParameters[5], deserialized.MethodParameters[5]); Assert.NotNull(deserialized.MethodParameters[6]); Assert.Equal(carrier.MethodParameters[6], deserialized.MethodParameters[6]); Assert.NotNull(deserialized.MethodParameters[7]); Assert.Equal(carrier.MethodParameters[7], deserialized.MethodParameters[7]); Assert.NotNull(deserialized.MethodParameters[8]); Assert.Equal(carrier.MethodParameters[8], deserialized.MethodParameters[8]); Assert.NotNull(deserialized.MethodParameters[9]); Assert.Equal(carrier.MethodParameters[9], deserialized.MethodParameters[9]); Assert.NotNull(deserialized.MethodParameters[10]); Assert.Equal(carrier.MethodParameters[10], deserialized.MethodParameters[10]); Assert.NotNull(deserialized.MethodParameters[11]); Assert.Equal(carrier.MethodParameters[11], deserialized.MethodParameters[11]); }
public void VM_ExecuteContract_WithoutParameters() { //Get the contract execution code------------------------ SmartContractCompilationResult compilationResult = SmartContractCompiler.CompileFile("SmartContracts/StorageTest.cs"); Assert.True(compilationResult.Success); byte[] contractExecutionCode = compilationResult.Compilation; //------------------------------------------------------- //Call smart contract and add to transaction------------- var carrier = SmartContractCarrier.CallContract(1, new uint160(1), "StoreData", 1, (Gas)500000); var transactionCall = new Transaction(); transactionCall.AddInput(new TxIn()); TxOut callTxOut = transactionCall.AddOutput(0, new Script(carrier.Serialize())); //------------------------------------------------------- //Deserialize the contract from the transaction---------- var deserializedCall = SmartContractCarrier.Deserialize(transactionCall); //------------------------------------------------------- var repository = new ContractStateRepositoryRoot(new NoDeleteSource <byte[], byte[]>(new MemoryDictionarySource())); IContractStateRepository stateRepository = repository.StartTracking(); var gasMeter = new GasMeter(deserializedCall.CallData.GasLimit); var persistenceStrategy = new MeteredPersistenceStrategy(repository, gasMeter, this.keyEncodingStrategy); var persistentState = new PersistentState(persistenceStrategy, deserializedCall.CallData.ContractAddress, this.network); var internalTxExecutorFactory = new InternalTransactionExecutorFactory(this.keyEncodingStrategy, this.loggerFactory, this.network); var vm = new ReflectionVirtualMachine(internalTxExecutorFactory, this.loggerFactory); var sender = deserializedCall.Sender?.ToString() ?? TestAddress.ToString(); var context = new SmartContractExecutionContext( new Block(1, new Address("2")), new Message( new Address(deserializedCall.CallData.ContractAddress.ToString()), new Address(sender), deserializedCall.Value, deserializedCall.CallData.GasLimit ), TestAddress.ToUint160(this.network), deserializedCall.CallData.GasPrice ); var result = vm.ExecuteMethod( contractExecutionCode, "StoreData", context, gasMeter, persistentState, repository); stateRepository.Commit(); Assert.Equal(Encoding.UTF8.GetBytes("TestValue"), stateRepository.GetStorageValue(deserializedCall.CallData.ContractAddress, Encoding.UTF8.GetBytes("TestKey"))); Assert.Equal(Encoding.UTF8.GetBytes("TestValue"), repository.GetStorageValue(deserializedCall.CallData.ContractAddress, Encoding.UTF8.GetBytes("TestKey"))); }
public void VM_CreateContract_WithParameters() { //Get the contract execution code------------------------ SmartContractCompilationResult compilationResult = SmartContractCompiler.CompileFile("SmartContracts/Auction.cs"); Assert.True(compilationResult.Success); byte[] contractExecutionCode = compilationResult.Compilation; //------------------------------------------------------- // //Call smart contract and add to transaction------------- string[] methodParameters = new string[] { string.Format("{0}#{1}", (int)SmartContractCarrierDataType.ULong, 5), }; var carrier = SmartContractCarrier.CreateContract(1, contractExecutionCode, 1, (Gas)500000, methodParameters); var transactionCall = new Transaction(); transactionCall.AddInput(new TxIn()); TxOut callTxOut = transactionCall.AddOutput(0, new Script(carrier.Serialize())); //------------------------------------------------------- //Deserialize the contract from the transaction---------- var deserializedCall = SmartContractCarrier.Deserialize(transactionCall); //------------------------------------------------------- var repository = new ContractStateRepositoryRoot(new NoDeleteSource <byte[], byte[]>(new MemoryDictionarySource())); IContractStateRepository track = repository.StartTracking(); var gasMeter = new GasMeter(deserializedCall.CallData.GasLimit); var persistenceStrategy = new MeteredPersistenceStrategy(repository, gasMeter, new BasicKeyEncodingStrategy()); var persistentState = new PersistentState(persistenceStrategy, TestAddress.ToUint160(this.network), this.network); var internalTxExecutorFactory = new InternalTransactionExecutorFactory(this.keyEncodingStrategy, this.loggerFactory, this.network); var vm = new ReflectionVirtualMachine(internalTxExecutorFactory, this.loggerFactory); var context = new SmartContractExecutionContext( new Block(1, TestAddress), new Message( TestAddress, TestAddress, deserializedCall.Value, deserializedCall.CallData.GasLimit ), TestAddress.ToUint160(this.network), deserializedCall.CallData.GasPrice, deserializedCall.MethodParameters ); var result = vm.Create( contractExecutionCode, context, gasMeter, persistentState, repository); track.Commit(); Assert.Equal(6, BitConverter.ToInt16(track.GetStorageValue(context.Message.ContractAddress.ToUint160(this.network), Encoding.UTF8.GetBytes("EndBlock")), 0)); Assert.Equal(TestAddress.ToUint160(this.network).ToBytes(), track.GetStorageValue(context.Message.ContractAddress.ToUint160(this.network), Encoding.UTF8.GetBytes("Owner"))); }