public override void Execute() { // Obtain our offsets and sizes for the copy. BigInteger memoryOffset = Stack.Pop(); BigInteger dataOffset = Stack.Pop(); BigInteger dataSize = Stack.Pop(); // This is considered a copy operation, so we charge for the size of the data. GasState.Deduct(GasDefinitions.GetMemoryCopyCost(Version, dataSize)); // Read our data from the code segment (if our offset is wrong or we hit the end of the array, the rest should be zeroes). byte[] data = new byte[(int)dataSize]; int length = data.Length; if (dataOffset > EVM.Code.Length) { dataOffset = 0; length = 0; } else if (dataOffset + length > EVM.Code.Length) { length = EVM.Code.Length - (int)dataOffset; } // Copy to the memory location. EVM.Code.Slice((int)dataOffset, length).CopyTo(data); // Write the data to our given memory offset. Memory.Write((long)memoryOffset, data); }
public override void Execute() { // Obtain our offsets and sizes for the copy. BigInteger memoryOffset = Stack.Pop(); BigInteger dataOffset = Stack.Pop(); BigInteger dataSize = Stack.Pop(); // This is considered a copy operation, so we charge for the size of the data. GasState.Deduct(GasDefinitions.GetMemoryCopyCost(Version, dataSize)); // If we aren't copying anything, we can stop. if (dataOffset + dataSize == 0) { return; } // Check we have a return result, and check it's bounds. if (ExecutionState.LastCallResult?.ReturnData == null) { throw new EVMException($"{Opcode.ToString()} tried to copy return data from last call, but no last return data exists."); } else if (dataOffset + dataSize > (ExecutionState.LastCallResult?.ReturnData.Length ?? 0)) { throw new EVMException($"{Opcode.ToString()} tried to copy return data past the end."); } else { // Otherwise we write our data we wish to copy to memory. Memory.Write((long)memoryOffset, ExecutionState.LastCallResult.ReturnData.Slice((int)dataOffset, (int)(dataSize)).ToArray()); } }