public (Money, TxOut) Process(ContractTxData contractTxData, ulong mempoolFee, uint160 sender, Gas gasConsumed, bool outOfGas) { this.logger.LogTrace("(){0}:{1}", nameof(mempoolFee), mempoolFee); Money fee = mempoolFee; if (outOfGas) { this.logger.LogTrace("(-)[OUTOFGAS_EXCEPTION]"); return(fee, null); } var refund = new Money(contractTxData.GasCostBudget - (gasConsumed * contractTxData.GasPrice)); this.logger.LogTrace("{0}:{1},{2}:{3},{4}:{5},{6}:{7}", nameof(contractTxData.GasCostBudget), contractTxData.GasCostBudget, nameof(gasConsumed), gasConsumed, nameof(contractTxData.GasPrice), contractTxData.GasPrice, nameof(refund), refund); TxOut ret = null; if (refund > 0) { fee -= refund; ret = CreateRefund(sender, refund); } this.logger.LogTrace("(-)"); return(fee, ret); }
public (Money, List <TxOut>) Process(ContractTxData contractTxData, ulong mempoolFee, uint160 sender, Gas gasConsumed, Exception exception) { this.logger.LogTrace("(){0}:{1}", nameof(mempoolFee), mempoolFee); Money fee = mempoolFee; var refunds = new List <TxOut>(); if (exception is OutOfGasException) { this.logger.LogTrace("(-)[OUTOFGAS_EXCEPTION]"); return(fee, refunds); } var refund = new Money(contractTxData.GasCostBudget - (gasConsumed * contractTxData.GasPrice)); this.logger.LogTrace("{0}:{1},{2}:{3},{4}:{5},{6}:{7}", nameof(contractTxData.GasCostBudget), contractTxData.GasCostBudget, nameof(gasConsumed), gasConsumed, nameof(contractTxData.GasPrice), contractTxData.GasPrice, nameof(refund), refund); if (refund > 0) { fee -= refund; refunds.Add(CreateRefund(sender, refund)); } this.logger.LogTrace("(-)"); return(fee, refunds); }
public byte[] Serialize(ContractTxData contractTxData) { var bytes = new List <byte> { contractTxData.OpCodeType }; bytes.AddRange(PrefixLength(BitConverter.GetBytes(contractTxData.VmVersion))); bytes.AddRange(PrefixLength(BitConverter.GetBytes(contractTxData.GasPrice))); bytes.AddRange(PrefixLength(BitConverter.GetBytes(contractTxData.GasLimit))); if (contractTxData.OpCodeType == (byte)ScOpcodeType.OP_CALLCONTRACT) { bytes.AddRange(PrefixLength(contractTxData.ContractAddress.ToBytes())); bytes.AddRange(PrefixLength(Encoding.UTF8.GetBytes(contractTxData.MethodName))); } if (contractTxData.OpCodeType == (byte)ScOpcodeType.OP_CREATECONTRACT) { bytes.AddRange(PrefixLength(contractTxData.ContractExecutionCode)); } if (contractTxData.MethodParameters != null && contractTxData.MethodParameters.Any()) { bytes.AddRange(PrefixLength(this.MethodParamSerializer.Serialize(contractTxData.MethodParameters))); } else { bytes.AddRange(BitConverter.GetBytes(0)); } return(bytes.ToArray()); }
private void SerializePrefix(byte[] bytes, ContractTxData contractTxData) { byte[] vmVersion = this.primitiveSerializer.Serialize(contractTxData.VmVersion); byte[] gasPrice = this.primitiveSerializer.Serialize(contractTxData.GasPrice); byte[] gasLimit = this.primitiveSerializer.Serialize(contractTxData.GasLimit.Value); bytes[0] = contractTxData.OpCodeType; vmVersion.CopyTo(bytes, OpcodeSize); gasPrice.CopyTo(bytes, OpcodeSize + VmVersionSize); gasLimit.CopyTo(bytes, OpcodeSize + VmVersionSize + GasPriceSize); }
private Result <ContractTxData> SerializeCreateContract(byte[] smartContractBytes, int vmVersion, ulong gasPrice, Gas gasLimit) { var remaining = smartContractBytes.Slice(PrefixSize, (uint)(smartContractBytes.Length - PrefixSize)); IList <byte[]> decodedParams = RLPDecode(remaining); var contractExecutionCode = this.primitiveSerializer.Deserialize <byte[]>(decodedParams[0]); var methodParameters = this.DeserializeMethodParameters(decodedParams[1]); var callData = new ContractTxData(vmVersion, gasPrice, gasLimit, contractExecutionCode, methodParameters); return(Result.Ok(callData)); }
private Result <ContractTxData> SerializeCallContract(byte[] smartContractBytes, int vmVersion, ulong gasPrice, Gas gasLimit) { var contractAddressBytes = smartContractBytes.Slice(PrefixSize, AddressSize); var contractAddress = new uint160(contractAddressBytes); var remaining = smartContractBytes.Slice(CallContractPrefixSize, (uint)(smartContractBytes.Length - CallContractPrefixSize)); IList <byte[]> decodedParams = RLPDecode(remaining); var methodName = this.primitiveSerializer.Deserialize <string>(decodedParams[0]); var methodParameters = this.DeserializeMethodParameters(decodedParams[1]); var callData = new ContractTxData(vmVersion, gasPrice, gasLimit, contractAddress, methodName, methodParameters); return(Result.Ok(callData)); }
private byte[] SerializeCreateContract(ContractTxData contractTxData) { var rlpBytes = new List <byte[]>(); rlpBytes.Add(contractTxData.ContractExecutionCode); this.AddMethodParams(rlpBytes, contractTxData.MethodParameters); var encoded = RLP.EncodeList(rlpBytes.Select(RLP.EncodeElement).ToArray()); var bytes = new byte[PrefixSize + encoded.Length]; this.SerializePrefix(bytes, contractTxData); encoded.CopyTo(bytes, PrefixSize); return(bytes); }
public Result <ContractTxData> Deserialize(byte[] smartContractBytes) { try { var byteCursor = 1; var takeLength = 0; var type = smartContractBytes[0]; var vmVersion = Deserialize <int>(smartContractBytes, ref byteCursor, ref takeLength); var gasPrice = (Gas)Deserialize <ulong>(smartContractBytes, ref byteCursor, ref takeLength); var gasLimit = (Gas)Deserialize <ulong>(smartContractBytes, ref byteCursor, ref takeLength); if (IsCallContract(type)) { var contractAddress = Deserialize <uint160>(smartContractBytes, ref byteCursor, ref takeLength); var methodName = Deserialize <string>(smartContractBytes, ref byteCursor, ref takeLength); var methodParametersRaw = Deserialize <string>(smartContractBytes, ref byteCursor, ref takeLength); var methodParameters = this.DeserializeMethodParameters(methodParametersRaw); var callData = new ContractTxData(vmVersion, gasPrice, gasLimit, contractAddress, methodName, methodParametersRaw, methodParameters); return(Result.Ok(callData)); } if (IsCreateContract(type)) { var contractExecutionCode = Deserialize <byte[]>(smartContractBytes, ref byteCursor, ref takeLength); var methodParametersRaw = Deserialize <string>(smartContractBytes, ref byteCursor, ref takeLength); var methodParameters = this.DeserializeMethodParameters(methodParametersRaw); var callData = new ContractTxData(vmVersion, gasPrice, gasLimit, contractExecutionCode, methodParametersRaw, methodParameters); return(Result.Ok(callData)); } } catch (Exception e) { // TODO: Avoid this catch all exceptions return(Result.Fail <ContractTxData>("Error deserializing calldata. " + e.Message)); } return(Result.Fail <ContractTxData>("Error deserializing calldata. Incorrect first byte.")); }
private byte[] SerializeCallContract(ContractTxData contractTxData) { var rlpBytes = new List <byte[]>(); rlpBytes.Add(this.primitiveSerializer.Serialize(contractTxData.MethodName)); this.AddMethodParams(rlpBytes, contractTxData.MethodParameters); var encoded = RLP.EncodeList(rlpBytes.Select(RLP.EncodeElement).ToArray()); var bytes = new byte[CallContractPrefixSize + encoded.Length]; this.SerializePrefix(bytes, contractTxData); contractTxData.ContractAddress.ToBytes().CopyTo(bytes, PrefixSize); encoded.CopyTo(bytes, CallContractPrefixSize); return(bytes); }
/// <summary> /// Instantiates a <see cref="ScOpcodeType.OP_CREATECONTRACT"/> smart contract carrier. /// </summary> public static ContractCarrier CreateContract(int vmVersion, byte[] contractExecutionCode, ulong gasPrice, Gas gasLimit, string[] methodParameters = null) { if (contractExecutionCode == null) { throw new SmartContractCarrierException(nameof(contractExecutionCode) + " is null"); } var serializer = new MethodParameterSerializer(); string methodParams = GetMethodParams(serializer, methodParameters); var callData = new ContractTxData(vmVersion, gasPrice, gasLimit, contractExecutionCode, methodParams); var carrier = new ContractCarrier(new MethodParameterSerializer()); carrier.ContractTxData = callData; if (!string.IsNullOrWhiteSpace(methodParams)) { carrier.MethodParameters = serializer.ToObjects(methodParams); } return(carrier); }
public ISmartContractExecutionResult Execute(ISmartContractTransactionContext transactionContext) { this.logger.LogTrace("()"); // Deserialization can't fail because this has already been through SmartContractFormatRule. Result <ContractTxData> callDataDeserializationResult = this.serializer.Deserialize(transactionContext.ScriptPubKey.ToBytes()); ContractTxData callData = callDataDeserializationResult.Value; var gasMeter = new GasMeter(callData.GasLimit); gasMeter.Spend((Gas)GasPriceList.BaseCost); var context = new TransactionContext( transactionContext.TransactionHash, transactionContext.BlockHeight, transactionContext.CoinbaseAddress, transactionContext.Sender, transactionContext.TxOutValue); var creation = IsCreateContract(callData); VmExecutionResult result = creation ? this.vm.Create(gasMeter, this.stateSnapshot, callData, context) : this.vm.ExecuteMethod(gasMeter, this.stateSnapshot, callData, context); var revert = result.ExecutionException != null; Transaction internalTransaction = this.transferProcessor.Process( this.stateSnapshot, creation ? result.NewContractAddress : callData.ContractAddress, transactionContext, result.InternalTransfers, revert); (Money fee, List <TxOut> refundTxOuts) = this.refundProcessor.Process( callData, transactionContext.MempoolFee, transactionContext.Sender, result.GasConsumed, result.ExecutionException); var executionResult = new SmartContractExecutionResult { NewContractAddress = !revert && creation ? result.NewContractAddress : null, Exception = result.ExecutionException, GasConsumed = result.GasConsumed, Return = result.Result, InternalTransaction = internalTransaction, Fee = fee, Refunds = refundTxOuts, Logs = result.RawLogs.ToLogs(this.contractPrimitiveSerializer) }; if (revert) { this.logger.LogTrace("(-)[CONTRACT_EXECUTION_FAILED]"); this.stateSnapshot.Rollback(); } else { this.logger.LogTrace("(-)[CONTRACT_EXECUTION_SUCCEEDED]"); this.stateSnapshot.Commit(); } return(executionResult); }
private static bool IsCreateContract(ContractTxData contractTxData) { return(contractTxData.OpCodeType == (byte)ScOpcodeType.OP_CREATECONTRACT); }
public byte[] Serialize(ContractTxData contractTxData) { return(IsCallContract(contractTxData.OpCodeType) ? this.SerializeCallContract(contractTxData) : this.SerializeCreateContract(contractTxData)); }
public IContractExecutionResult Execute(IContractTransactionContext transactionContext) { // Deserialization can't fail because this has already been through SmartContractFormatRule. Result <ContractTxData> callDataDeserializationResult = this.serializer.Deserialize(transactionContext.Data); ContractTxData callData = callDataDeserializationResult.Value; bool creation = callData.IsCreateContract; var block = new Block( transactionContext.BlockHeight, transactionContext.CoinbaseAddress.ToAddress(this.network) ); IState state = this.stateFactory.Create( this.stateRoot, block, transactionContext.TxOutValue, transactionContext.TransactionHash); StateTransitionResult result; IState newState = state.Snapshot(); if (creation) { var message = new ExternalCreateMessage( transactionContext.Sender, transactionContext.TxOutValue, callData.GasLimit, callData.ContractExecutionCode, callData.MethodParameters ); result = this.stateProcessor.Apply(newState, message); } else { var message = new ExternalCallMessage( callData.ContractAddress, transactionContext.Sender, transactionContext.TxOutValue, callData.GasLimit, new MethodCall(callData.MethodName, callData.MethodParameters) ); result = this.stateProcessor.Apply(newState, message); } if (result.IsSuccess) { state.TransitionTo(newState); } bool revert = !result.IsSuccess; Transaction internalTransaction = this.transferProcessor.Process( this.stateRoot, result.Success?.ContractAddress, transactionContext, state.InternalTransfers, revert); bool outOfGas = result.IsFailure && result.Error.Kind == StateTransitionErrorKind.OutOfGas; (Money fee, TxOut refundTxOut) = this.refundProcessor.Process( callData, transactionContext.MempoolFee, transactionContext.Sender, result.GasConsumed, outOfGas); var executionResult = new SmartContractExecutionResult { To = !callData.IsCreateContract ? callData.ContractAddress : null, NewContractAddress = !revert && creation ? result.Success?.ContractAddress : null, ErrorMessage = result.Error?.GetErrorMessage(), Revert = revert, GasConsumed = result.GasConsumed, Return = result.Success?.ExecutionResult, InternalTransaction = internalTransaction, Fee = fee, Refund = refundTxOut, Logs = state.GetLogs(this.contractPrimitiveSerializer) }; return(executionResult); }